# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
use strict;
package CPAN;
$CPAN::VERSION = '2.33';
$CPAN::VERSION =~ s/_//;

# we need to run chdir all over and we would get at wrong libraries
# there
use File::Spec ();
BEGIN {
    if (File::Spec->can("rel2abs")) {
        for my $inc (@INC) {
            $inc = File::Spec->rel2abs($inc) unless ref $inc;
        }
    }
    $SIG{WINCH} = 'IGNORE' if exists $SIG{WINCH};
}
use CPAN::Author;
use CPAN::HandleConfig;
use CPAN::Version;
use CPAN::Bundle;
use CPAN::CacheMgr;
use CPAN::Complete;
use CPAN::Debug;
use CPAN::Distribution;
use CPAN::Distrostatus;
use CPAN::FTP;
use CPAN::Index 1.93; # https://rt.cpan.org/Ticket/Display.html?id=43349
use CPAN::InfoObj;
use CPAN::Module;
use CPAN::Prompt;
use CPAN::URL;
use CPAN::Queue;
use CPAN::Tarzip;
use CPAN::DeferredCode;
use CPAN::Shell;
use CPAN::LWP::UserAgent;
use CPAN::Exception::RecursiveDependency;
use CPAN::Exception::yaml_not_installed;
use CPAN::Exception::yaml_process_error;

use Carp ();
use Config ();
use Cwd qw(chdir);
use DirHandle ();
use Exporter ();
use ExtUtils::MakeMaker qw(prompt); # for some unknown reason,
                                    # 5.005_04 does not work without
                                    # this
use File::Basename ();
use File::Copy ();
use File::Find;
use File::Path ();
use FileHandle ();
use Fcntl qw(:flock);
use Safe ();
use Sys::Hostname qw(hostname);
use Text::ParseWords ();
use Text::Wrap ();

# protect against "called too early"
sub find_perl ();
sub anycwd ();
sub _uniq;

no lib ".";

require Mac::BuildTools if $^O eq 'MacOS';
if ($ENV{PERL5_CPAN_IS_RUNNING} && $$ != $ENV{PERL5_CPAN_IS_RUNNING}) {
    $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} ||= $ENV{PERL5_CPAN_IS_RUNNING};
    my @rec = _uniq split(/,/, $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION}), $$;
    $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} = join ",", @rec;
    # warn "# Note: Recursive call of CPAN.pm detected\n";
    my $w = sprintf "# Note: CPAN.pm is running in process %d now", pop @rec;
    my %sleep = (
                 5 => 30,
                 6 => 60,
                 7 => 120,
                );
    my $sleep = @rec > 7 ? 300 : ($sleep{scalar @rec}||0);
    my $verbose = @rec >= 4;
    while (@rec) {
        $w .= sprintf " which has been called by process %d", pop @rec;
    }
    if ($sleep) {
        $w .= ".\n\n# Sleeping $sleep seconds to protect other processes\n";
    }
    if ($verbose) {
        warn $w;
    }
    local $| = 1;
    my $have_been_sleeping = 0;
    while ($sleep > 0) {
        printf "\r#%5d", --$sleep;
        sleep 1;
	++$have_been_sleeping;
    }
    print "\n" if $have_been_sleeping;
}
$ENV{PERL5_CPAN_IS_RUNNING}=$$;
$ENV{PERL5_CPANPLUS_IS_RUNNING}=$$; # https://rt.cpan.org/Ticket/Display.html?id=23735

END { $CPAN::End++; &cleanup; }

$CPAN::Signal ||= 0;
$CPAN::Frontend ||= "CPAN::Shell";
unless (@CPAN::Defaultsites) {
    @CPAN::Defaultsites = map {
        CPAN::URL->new(TEXT => $_, FROM => "DEF")
    }
        "http://www.perl.org/CPAN/",
        "ftp://ftp.perl.org/pub/CPAN/";
}
# $CPAN::iCwd (i for initial)
$CPAN::iCwd ||= CPAN::anycwd();
$CPAN::Perl ||= CPAN::find_perl();
$CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
$CPAN::Defaultrecent ||= "http://search.cpan.org/uploads.rdf";
$CPAN::Defaultrecent ||= "http://cpan.uwinnipeg.ca/htdocs/cpan.xml";

# our globals are getting a mess
use vars qw(
            $AUTOLOAD
            $Be_Silent
            $CONFIG_DIRTY
            $Defaultdocs
            $Echo_readline
            $Frontend
            $GOTOSHELL
            $HAS_USABLE
            $Have_warned
            $MAX_RECURSION
            $META
            $RUN_DEGRADED
            $Signal
            $SQLite
            $Suppress_readline
            $VERSION
            $autoload_recursion
            $term
            @Defaultsites
            @EXPORT
           );

$MAX_RECURSION = 32;

@CPAN::ISA = qw(CPAN::Debug Exporter);

# note that these functions live in CPAN::Shell and get executed via
# AUTOLOAD when called directly
@EXPORT = qw(
             autobundle
             bundle
             clean
             cvs_import
             expand
             force
             fforce
             get
             install
             install_tested
             is_tested
             make
             mkmyconfig
             notest
             perldoc
             readme
             recent
             recompile
             report
             shell
             smoke
             test
             upgrade
            );

sub soft_chdir_with_alternatives ($);

{
    $autoload_recursion ||= 0;

    #-> sub CPAN::AUTOLOAD ;
    sub AUTOLOAD { ## no critic
        $autoload_recursion++;
        my($l) = $AUTOLOAD;
        $l =~ s/.*:://;
        if ($CPAN::Signal) {
            warn "Refusing to autoload '$l' while signal pending";
            $autoload_recursion--;
            return;
        }
        if ($autoload_recursion > 1) {
            my $fullcommand = join " ", map { "'$_'" } $l, @_;
            warn "Refusing to autoload $fullcommand in recursion\n";
            $autoload_recursion--;
            return;
        }
        my(%export);
        @export{@EXPORT} = '';
        CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
        if (exists $export{$l}) {
            CPAN::Shell->$l(@_);
        } else {
            die(qq{Unknown CPAN command "$AUTOLOAD". }.
                qq{Type ? for help.\n});
        }
        $autoload_recursion--;
    }
}

{
    my $x = *SAVEOUT; # avoid warning
    open($x,">&STDOUT") or die "dup failed";
    my $redir = 0;
    sub _redirect(@) {
        #die if $redir;
        local $_;
        push(@_,undef);
        while(defined($_=shift)) {
            if (s/^\s*>//){
                my ($m) = s/^>// ? ">" : "";
                s/\s+//;
                $_=shift unless length;
                die "no dest" unless defined;
                open(STDOUT,">$m$_") or die "open:$_:$!\n";
                $redir=1;
            } elsif ( s/^\s*\|\s*// ) {
                my $pipe="| $_";
                while(defined($_[0])){
                    $pipe .= ' ' . shift;
                }
                open(STDOUT,$pipe) or die "open:$pipe:$!\n";
                $redir=1;
            } else {
                push(@_,$_);
            }
        }
        return @_;
    }
    sub _unredirect {
        return unless $redir;
        $redir = 0;
        ## redirect: unredirect and propagate errors.  explicit close to wait for pipe.
        close(STDOUT);
        open(STDOUT,">&SAVEOUT");
        die "$@" if "$@";
        ## redirect: done
    }
}

sub _uniq {
    my(@list) = @_;
    my %seen;
    return grep { !$seen{$_}++ } @list;
}

#-> sub CPAN::shell ;
sub shell {
    my($self) = @_;
    $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;

    my $oprompt = shift || CPAN::Prompt->new;
    my $prompt = $oprompt;
    my $commandline = shift || "";
    $CPAN::CurrentCommandId ||= 1;

    local($^W) = 1;
    unless ($Suppress_readline) {
        require Term::ReadLine;
        if (! $term
            or
            $term->ReadLine eq "Term::ReadLine::Stub"
           ) {
            $term = Term::ReadLine->new('CPAN Monitor');
        }
        if ($term->ReadLine eq "Term::ReadLine::Gnu") {
            my $attribs = $term->Attribs;
            $attribs->{attempted_completion_function} = sub {
                &CPAN::Complete::gnu_cpl;
            }
        } else {
            $readline::rl_completion_function =
                $readline::rl_completion_function = 'CPAN::Complete::cpl';
        }
        if (my $histfile = $CPAN::Config->{'histfile'}) {{
            unless ($term->can("AddHistory")) {
                $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
                unless ($CPAN::META->has_inst('Term::ReadLine::Perl')) {
                    $CPAN::Frontend->mywarn("\nTo fix that, maybe try>  install Term::ReadLine::Perl\n\n");
                }
                last;
            }
            $META->readhist($term,$histfile);
        }}
        for ($CPAN::Config->{term_ornaments}) { # alias
            local $Term::ReadLine::termcap_nowarn = 1;
            $term->ornaments($_) if defined;
        }
        # $term->OUT is autoflushed anyway
        my $odef = select STDERR;
        $| = 1;
        select STDOUT;
        $| = 1;
        select $odef;
    }

    $META->checklock();
    my @cwd = grep { defined $_ and length $_ }
        CPAN::anycwd(),
              File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
                    File::Spec->rootdir();
    my $try_detect_readline;
    $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
    unless ($CPAN::Config->{inhibit_startup_message}) {
        my $rl_avail = $Suppress_readline ? "suppressed" :
            ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
                "available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
        $CPAN::Frontend->myprint(
                                 sprintf qq{
cpan shell -- CPAN exploration and modules installation (v%s)
Enter 'h' for help.

},
                                 $CPAN::VERSION,
                                )
    }
    my($continuation) = "";
    my $last_term_ornaments;
  SHELLCOMMAND: while () {
        if ($Suppress_readline) {
            if ($Echo_readline) {
                $|=1;
            }
            print $prompt;
            last SHELLCOMMAND unless defined ($_ = <> );
            if ($Echo_readline) {
                # backdoor: I could not find a way to record sessions
                print $_;
            }
            chomp;
        } else {
            last SHELLCOMMAND unless
                defined ($_ = $term->readline($prompt, $commandline));
        }
        $_ = "$continuation$_" if $continuation;
        s/^\s+//;
        next SHELLCOMMAND if /^$/;
        s/^\s*\?\s*/help /;
        if (/^(?:q(?:uit)?|bye|exit)\s*$/i) {
            last SHELLCOMMAND;
        } elsif (s/\\$//s) {
            chomp;
            $continuation = $_;
            $prompt = "    > ";
        } elsif (/^\!/) {
            s/^\!//;
            my($eval) = $_;
            package
                CPAN::Eval; # hide from the indexer
            use strict;
            use vars qw($import_done);
            CPAN->import(':DEFAULT') unless $import_done++;
            CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
            eval($eval);
            warn $@ if $@;
            $continuation = "";
            $prompt = $oprompt;
        } elsif (/./) {
            my(@line);
            eval { @line = Text::ParseWords::shellwords($_) };
            warn($@), next SHELLCOMMAND if $@;
            warn("Text::Parsewords could not parse the line [$_]"),
                next SHELLCOMMAND unless @line;
            $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
            my $command = shift @line;
            eval {
                local (*STDOUT)=*STDOUT;
                @line = _redirect(@line);
                CPAN::Shell->$command(@line)
              };
            my $command_error = $@;
            _unredirect;
            my $reported_error;
            if ($command_error) {
                my $err = $command_error;
                if (ref $err and $err->isa('CPAN::Exception::blocked_urllist')) {
                    $CPAN::Frontend->mywarn("Client not fully configured, please proceed with configuring.$err");
                    $reported_error = ref $err;
                } else {
                    # I'd prefer never to arrive here and make all errors exception objects
                    if ($err =~ /\S/) {
                        require Carp;
                        require Dumpvalue;
                        my $dv = Dumpvalue->new(tick => '"');
                        Carp::cluck(sprintf "Catching error: %s", $dv->stringify($err));
                    }
                }
            }
            if ($command =~ /^(
                             # classic commands
                             make
                             |test
                             |install
                             |clean

                             # pragmas for classic commands
                             |ff?orce
                             |notest

                             # compounds
                             |report
                             |smoke
                             |upgrade
                            )$/x) {
                # only commands that tell us something about failed distros
                # eval necessary for people without an urllist
                eval {CPAN::Shell->failed($CPAN::CurrentCommandId,1);};
                if (my $err = $@) {
                    unless (ref $err and $reported_error eq ref $err) {
                        die $@;
                    }
                }
            }
            soft_chdir_with_alternatives(\@cwd);
            $CPAN::Frontend->myprint("\n");
            $continuation = "";
            $CPAN::CurrentCommandId++;
            $prompt = $oprompt;
        }
    } continue {
        $commandline = ""; # I do want to be able to pass a default to
                           # shell, but on the second command I see no
                           # use in that
        $Signal=0;
        CPAN::Queue->nullify_queue;
        if ($try_detect_readline) {
            if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
                ||
                $CPAN::META->has_inst("Term::ReadLine::Perl")
            ) {
                delete $INC{"Term/ReadLine.pm"};
                my $redef = 0;
                local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
                require Term::ReadLine;
                $CPAN::Frontend->myprint("\n$redef subroutines in ".
                                         "Term::ReadLine redefined\n");
                $GOTOSHELL = 1;
            }
        }
        if ($term and $term->can("ornaments")) {
            for ($CPAN::Config->{term_ornaments}) { # alias
                if (defined $_) {
                    if (not defined $last_term_ornaments
                        or $_ != $last_term_ornaments
                    ) {
                        local $Term::ReadLine::termcap_nowarn = 1;
                        $term->ornaments($_);
                        $last_term_ornaments = $_;
                    }
                } else {
                    undef $last_term_ornaments;
                }
            }
        }
        for my $class (qw(Module Distribution)) {
            # again unsafe meta access?
            for my $dm (sort keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
                next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
                CPAN->debug("BUG: $class '$dm' was in command state, resetting");
                delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
            }
        }
        if ($GOTOSHELL) {
            $GOTOSHELL = 0; # not too often
            $META->savehist if $CPAN::term && $CPAN::term->can("GetHistory");
            @_ = ($oprompt,"");
            goto &shell;
        }
    }
    soft_chdir_with_alternatives(\@cwd);
}

#-> CPAN::soft_chdir_with_alternatives ;
sub soft_chdir_with_alternatives ($) {
    my($cwd) = @_;
    unless (@$cwd) {
        my $root = File::Spec->rootdir();
        $CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
Trying '$root' as temporary haven.
});
        push @$cwd, $root;
    }
    while () {
        if (chdir "$cwd->[0]") {
            return;
        } else {
            if (@$cwd>1) {
                $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
Trying to chdir to "$cwd->[1]" instead.
});
                shift @$cwd;
            } else {
                $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
            }
        }
    }
}

sub _flock {
    my($fh,$mode) = @_;
    if ( $Config::Config{d_flock} || $Config::Config{d_fcntl_can_lock} ) {
        return flock $fh, $mode;
    } elsif (!$Have_warned->{"d_flock"}++) {
        $CPAN::Frontend->mywarn("Your OS does not seem to support locking; continuing and ignoring all locking issues\n");
        $CPAN::Frontend->mysleep(5);
        return 1;
    } else {
        return 1;
    }
}

sub _yaml_module () {
    my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
    if (
        $yaml_module ne "YAML"
        &&
        !$CPAN::META->has_inst($yaml_module)
       ) {
        # $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
        $yaml_module = "YAML";
    }
    if ($yaml_module eq "YAML"
        &&
        $CPAN::META->has_inst($yaml_module)
        &&
        $YAML::VERSION < 0.60
        &&
        !$Have_warned->{"YAML"}++
       ) {
        $CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
                                "I'll continue but problems are *very* likely to happen.\n"
                               );
        $CPAN::Frontend->mysleep(5);
    }
    return $yaml_module;
}

# CPAN::_yaml_loadfile
sub _yaml_loadfile {
    my($self,$local_file,$opt) = @_;
    return +[] unless -s $local_file;
    my $opt_loadblessed = $opt->{loadblessed} || $CPAN::Config->{yaml_load_code} || 0;
    my $yaml_module = _yaml_module;
    if ($CPAN::META->has_inst($yaml_module)) {
        # temporarily enable yaml code deserialisation
        no strict 'refs';
        # 5.6.2 could not do the local() with the reference
        # so we do it manually instead
        my $old_loadcode = ${"$yaml_module\::LoadCode"};
        my $old_loadblessed = ${"$yaml_module\::LoadBlessed"};
        ${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
        ${ "$yaml_module\::LoadBlessed" } = $opt_loadblessed ? 1 : 0;

        my ($code, @yaml);
        if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
            eval { @yaml = $code->($local_file); };
            if ($@) {
                # this shall not be done by the frontend
                die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
            }
        } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
            local *FH;
            if (open FH, $local_file) {
                local $/;
                my $ystream = <FH>;
                eval { @yaml = $code->($ystream); };
                if ($@) {
                    # this shall not be done by the frontend
                    die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
                }
            } else {
                $CPAN::Frontend->mywarn("Could not open '$local_file': $!");
            }
        }
        ${"$yaml_module\::LoadCode"} = $old_loadcode;
        ${"$yaml_module\::LoadBlessed"} = $old_loadblessed;
        return \@yaml;
    } else {
        # this shall not be done by the frontend
        die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
    }
    return +[];
}

# CPAN::_yaml_dumpfile
sub _yaml_dumpfile {
    my($self,$local_file,@what) = @_;
    my $yaml_module = _yaml_module;
    if ($CPAN::META->has_inst($yaml_module)) {
        my $code;
        if (UNIVERSAL::isa($local_file, "FileHandle")) {
            $code = UNIVERSAL::can($yaml_module, "Dump");
            eval { print $local_file $code->(@what) };
        } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
            eval { $code->($local_file,@what); };
        } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
            local *FH;
            open FH, ">$local_file" or die "Could not open '$local_file': $!";
            print FH $code->(@what);
        }
        if ($@) {
            die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
        }
    } else {
        if (UNIVERSAL::isa($local_file, "FileHandle")) {
            # I think this case does not justify a warning at all
        } else {
            die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
        }
    }
}

sub _init_sqlite () {
    unless ($CPAN::META->has_inst("CPAN::SQLite")) {
        $CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
            unless $Have_warned->{"CPAN::SQLite"}++;
        return;
    }
    require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
    $CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
}

{
    my $negative_cache = {};
    sub _sqlite_running {
        if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
            # need to cache the result, otherwise too slow
            return $negative_cache->{fact};
        } else {
            $negative_cache = {}; # reset
        }
        my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
        return $ret if $ret; # fast anyway
        $negative_cache->{time} = time;
        return $negative_cache->{fact} = $ret;
    }
}

$META ||= CPAN->new; # In case we re-eval ourselves we need the ||

# from here on only subs.
################################################################################

sub _perl_fingerprint {
    my($self,$other_fingerprint) = @_;
    my $dll = eval {OS2::DLLname()};
    my $mtime_dll = 0;
    if (defined $dll) {
        $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
    }
    my $mtime_perl = (-f CPAN::find_perl ? (stat(_))[9] : '-1');
    my $this_fingerprint = {
                            '$^X' => CPAN::find_perl,
                            sitearchexp => $Config::Config{sitearchexp},
                            'mtime_$^X' => $mtime_perl,
                            'mtime_dll' => $mtime_dll,
                           };
    if ($other_fingerprint) {
        if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
            $other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
        }
        # mandatory keys since 1.88_57
        for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
            return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
        }
        return 1;
    } else {
        return $this_fingerprint;
    }
}

sub suggest_myconfig () {
  SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
        $CPAN::Frontend->myprint("You don't seem to have a user ".
                                 "configuration (MyConfig.pm) yet.\n");
        my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
                                              "user configuration now? (Y/n)",
                                              "yes");
        if($new =~ m{^y}i) {
            CPAN::Shell->mkmyconfig();
            return &checklock;
        } else {
            $CPAN::Frontend->mydie("OK, giving up.");
        }
    }
}

#-> sub CPAN::all_objects ;
sub all_objects {
    my($mgr,$class) = @_;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
    CPAN::Index->reload;
    values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
}

# Called by shell, not in batch mode. In batch mode I see no risk in
# having many processes updating something as installations are
# continually checked at runtime. In shell mode I suspect it is
# unintentional to open more than one shell at a time

#-> sub CPAN::checklock ;
sub checklock {
    my($self) = @_;
    my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
    if (-f $lockfile && -M _ > 0) {
        my $fh = FileHandle->new($lockfile) or
            $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
        my $otherpid  = <$fh>;
        my $otherhost = <$fh>;
        $fh->close;
        if (defined $otherpid && length $otherpid) {
            chomp $otherpid;
        }
        if (defined $otherhost && length $otherhost) {
            chomp $otherhost;
        }
        my $thishost  = hostname();
        my $ask_if_degraded_wanted = 0;
        if (defined $otherhost && defined $thishost &&
            $otherhost ne '' && $thishost ne '' &&
            $otherhost ne $thishost) {
            $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
                                           "reports other host $otherhost and other ".
                                           "process $otherpid.\n".
                                           "Cannot proceed.\n"));
        } elsif ($RUN_DEGRADED) {
            $CPAN::Frontend->mywarn("Running in downgraded mode (experimental)\n");
        } elsif (defined $otherpid && $otherpid) {
            return if $$ == $otherpid; # should never happen
            $CPAN::Frontend->mywarn(
                                    qq{
There seems to be running another CPAN process (pid $otherpid).  Contacting...
});
            if (kill 0, $otherpid or $!{EPERM}) {
                $CPAN::Frontend->mywarn(qq{Other job is running.\n});
                $ask_if_degraded_wanted = 1;
            } elsif (-w $lockfile) {
                my($ans) =
                    CPAN::Shell::colorable_makemaker_prompt
                        (qq{Other job not responding. Shall I overwrite }.
                        qq{the lockfile '$lockfile'? (Y/n)},"y");
            $CPAN::Frontend->myexit("Ok, bye\n")
                unless $ans =~ /^y/i;
            } else {
                Carp::croak(
                    qq{Lockfile '$lockfile' not writable by you. }.
                    qq{Cannot proceed.\n}.
                    qq{    On UNIX try:\n}.
                    qq{    rm '$lockfile'\n}.
                    qq{  and then rerun us.\n}
                );
            }
        } elsif ($^O eq "MSWin32") {
            $CPAN::Frontend->mywarn(
                                    qq{
There seems to be running another CPAN process according to '$lockfile'.
});
            $ask_if_degraded_wanted = 1;
        } else {
            $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
                                           "'$lockfile', please remove. Cannot proceed.\n"));
        }
        if ($ask_if_degraded_wanted) {
            my($ans) =
                CPAN::Shell::colorable_makemaker_prompt
                    (qq{Shall I try to run in downgraded }.
                     qq{mode? (Y/n)},"y");
            if ($ans =~ /^y/i) {
                $CPAN::Frontend->mywarn("Running in downgraded mode (experimental).
Please report if something unexpected happens\n");
                $RUN_DEGRADED = 1;
                for ($CPAN::Config) {
                    # XXX
                    # $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
                    $_->{commandnumber_in_prompt} = 0; # visibility
                    $_->{histfile}       = "";  # who should win otherwise?
                    $_->{cache_metadata} = 0;   # better would be a lock?
                    $_->{use_sqlite}     = 0;   # better would be a write lock!
                    $_->{auto_commit}    = 0;   # we are violent, do not persist
                    $_->{test_report}    = 0;   # Oliver Paukstadt had sent wrong reports in degraded mode
                }
            } else {
                my $msg = "You may want to kill the other job and delete the lockfile.";
                if (defined $otherpid) {
                    $msg .= " Something like:
    kill $otherpid
    rm $lockfile
";
                }
                $CPAN::Frontend->mydie("\n$msg");
            }
        }
    }
    my $dotcpan = $CPAN::Config->{cpan_home};
    eval { File::Path::mkpath($dotcpan);};
    if ($@) {
        # A special case at least for Jarkko.
        my $firsterror = $@;
        my $seconderror;
        my $symlinkcpan;
        if (-l $dotcpan) {
            $symlinkcpan = readlink $dotcpan;
            die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
            eval { File::Path::mkpath($symlinkcpan); };
            if ($@) {
                $seconderror = $@;
            } else {
                $CPAN::Frontend->mywarn(qq{
Working directory $symlinkcpan created.
});
            }
        }
        unless (-d $dotcpan) {
            my $mess = qq{
Your configuration suggests "$dotcpan" as your
CPAN.pm working directory. I could not create this directory due
to this error: $firsterror\n};
            $mess .= qq{
As "$dotcpan" is a symlink to "$symlinkcpan",
I tried to create that, but I failed with this error: $seconderror
} if $seconderror;
            $mess .= qq{
Please make sure the directory exists and is writable.
};
            $CPAN::Frontend->mywarn($mess);
            return suggest_myconfig;
        }
    } # $@ after eval mkpath $dotcpan
    if (0) { # to test what happens when a race condition occurs
        for (reverse 1..10) {
            print $_, "\n";
            sleep 1;
        }
    }
    # locking
    if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
        my $fh;
        unless ($fh = FileHandle->new("+>>$lockfile")) {
            $CPAN::Frontend->mywarn(qq{

Your configuration suggests that CPAN.pm should use a working
directory of
    $CPAN::Config->{cpan_home}
Unfortunately we could not create the lock file
    $lockfile
due to '$!'.

Please make sure that the configuration variable
    \$CPAN::Config->{cpan_home}
points to a directory where you can write a .lock file. You can set
this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
\@INC path;
});
            return suggest_myconfig;
        }
        my $sleep = 1;
        while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
            my $err = $! || "unknown error";
            if ($sleep>3) {
                $CPAN::Frontend->mydie("Could not lock '$lockfile' with flock: $err; giving up\n");
            }
            $CPAN::Frontend->mysleep($sleep+=0.1);
            $CPAN::Frontend->mywarn("Could not lock '$lockfile' with flock: $err; retrying\n");
        }

        seek $fh, 0, 0;
        truncate $fh, 0;
        $fh->autoflush(1);
        $fh->print($$, "\n");
        $fh->print(hostname(), "\n");
        $self->{LOCK} = $lockfile;
        $self->{LOCKFH} = $fh;
    }
    $SIG{TERM} = sub {
        my $sig = shift;
        &cleanup;
        $CPAN::Frontend->mydie("Got SIG$sig, leaving");
    };
    $SIG{INT} = sub {
      # no blocks!!!
        my $sig = shift;
        &cleanup if $Signal;
        die "Got yet another signal" if $Signal > 1;
        $CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
        $CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
        $Signal++;
    };

#       From: Larry Wall <larry@wall.org>
#       Subject: Re: deprecating SIGDIE
#       To: perl5-porters@perl.org
#       Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
#
#       The original intent of __DIE__ was only to allow you to substitute one
#       kind of death for another on an application-wide basis without respect
#       to whether you were in an eval or not.  As a global backstop, it should
#       not be used any more lightly (or any more heavily :-) than class
#       UNIVERSAL.  Any attempt to build a general exception model on it should
#       be politely squashed.  Any bug that causes every eval {} to have to be
#       modified should be not so politely squashed.
#
#       Those are my current opinions.  It is also my opinion that polite
#       arguments degenerate to personal arguments far too frequently, and that
#       when they do, it's because both people wanted it to, or at least didn't
#       sufficiently want it not to.
#
#       Larry

    # global backstop to cleanup if we should really die
    $SIG{__DIE__} = \&cleanup;
    $self->debug("Signal handler set.") if $CPAN::DEBUG;
}

#-> sub CPAN::DESTROY ;
sub DESTROY {
    &cleanup; # need an eval?
}

#-> sub CPAN::anycwd ;
sub anycwd () {
    my $getcwd;
    $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
    CPAN->$getcwd();
}

#-> sub CPAN::cwd ;
sub cwd {Cwd::cwd();}

#-> sub CPAN::getcwd ;
sub getcwd {Cwd::getcwd();}

#-> sub CPAN::fastcwd ;
sub fastcwd {Cwd::fastcwd();}

#-> sub CPAN::getdcwd ;
sub getdcwd {Cwd::getdcwd();}

#-> sub CPAN::backtickcwd ;
sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}

# Adapted from Probe::Perl
#-> sub CPAN::_perl_is_same
sub _perl_is_same {
  my ($perl) = @_;
  return MM->maybe_command($perl)
    && `$perl -MConfig=myconfig -e print -e myconfig` eq Config->myconfig;
}

# Adapted in part from Probe::Perl
#-> sub CPAN::find_perl ;
sub find_perl () {
    if ( File::Spec->file_name_is_absolute($^X) ) {
        return $^X;
    }
    else {
        my $exe = $Config::Config{exe_ext};
        my @candidates = (
            File::Spec->catfile($CPAN::iCwd,$^X),
            $Config::Config{'perlpath'},
        );
        for my $perl_name ($^X, 'perl', 'perl5', "perl$]") {
            for my $path (File::Spec->path(), $Config::Config{'binexp'}) {
                if ( defined($path) && length $path && -d $path ) {
                    my $perl = File::Spec->catfile($path,$perl_name);
                    push @candidates, $perl;
                    # try with extension if not provided already
                    if ($^O eq 'VMS') {
                        # VMS might have a file version at the end
                        push @candidates, $perl . $exe
                            unless $perl =~ m/$exe(;\d+)?$/i;
                    } elsif (defined $exe && length $exe) {
                        push @candidates, $perl . $exe
                            unless $perl =~ m/$exe$/i;
                    }
                }
            }
        }
        for my $perl ( @candidates ) {
            if (MM->maybe_command($perl) && _perl_is_same($perl)) {
                $^X = $perl;
                return $perl;
            }
        }
    }
    return $^X; # default fall back
}

#-> sub CPAN::exists ;
sub exists {
    my($mgr,$class,$id) = @_;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    CPAN::Index->reload;
    ### Carp::croak "exists called without class argument" unless $class;
    $id ||= "";
    $id =~ s/:+/::/g if $class eq "CPAN::Module";
    my $exists;
    if (CPAN::_sqlite_running) {
        $exists = (exists $META->{readonly}{$class}{$id} or
                   $CPAN::SQLite->set($class, $id));
    } else {
        $exists =  exists $META->{readonly}{$class}{$id};
    }
    $exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}

#-> sub CPAN::delete ;
sub delete {
  my($mgr,$class,$id) = @_;
  delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
  delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}

#-> sub CPAN::has_usable
# has_inst is sometimes too optimistic, we should replace it with this
# has_usable whenever a case is given
sub has_usable {
    my($self,$mod,$message) = @_;
    return 1 if $HAS_USABLE->{$mod};
    my $has_inst = $self->has_inst($mod,$message);
    return unless $has_inst;
    my $usable;
    $usable = {

               #
               # most of these subroutines warn on the frontend, then
               # die if the installed version is unusable for some
               # reason; has_usable() then returns false when it caught
               # an exception, otherwise returns true and caches that;
               #
               'CPAN::Meta' => [
                            sub {
                                require CPAN::Meta;
                                unless (CPAN::Version->vge(CPAN::Meta->VERSION, 2.110350)) {
                                    for ("Will not use CPAN::Meta, need version 2.110350\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               'CPAN::Meta::Requirements' => [
                            sub {
                                if (defined $CPAN::Meta::Requirements::VERSION
                                    && CPAN::Version->vlt($CPAN::Meta::Requirements::VERSION, "2.120920")
                                   ) {
                                    delete $INC{"CPAN/Meta/Requirements.pm"};
                                }
                                require CPAN::Meta::Requirements;
                                unless (CPAN::Version->vge(CPAN::Meta::Requirements->VERSION, 2.120920)) {
                                    for ("Will not use CPAN::Meta::Requirements, need version 2.120920\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               'CPAN::Reporter' => [
                            sub {
                                if (defined $CPAN::Reporter::VERSION
                                    && CPAN::Version->vlt($CPAN::Reporter::VERSION, "1.2011")
                                   ) {
                                    delete $INC{"CPAN/Reporter.pm"};
                                }
                                require CPAN::Reporter;
                                unless (CPAN::Version->vge(CPAN::Reporter->VERSION, "1.2011")) {
                                    for ("Will not use CPAN::Reporter, need version 1.2011\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               LWP => [ # we frequently had "Can't locate object
                        # method "new" via package "LWP::UserAgent" at
                        # (eval 69) line 2006
                       sub {require LWP},
                       sub {require LWP::UserAgent},
                       sub {require HTTP::Request},
                       sub {require URI::URL;
                            unless (CPAN::Version->vge(URI::URL::->VERSION,0.08)) {
                                for ("Will not use URI::URL, need 0.08\n") {
                                    $CPAN::Frontend->mywarn($_);
                                    die $_;
                                }
                            }
                       },
                      ],
               'Net::FTP' => [
                            sub {
                                my $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
                                if ($var and $var =~ /^http:/i) {
                                    # rt #110833
                                    for ("Net::FTP cannot handle http proxy") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                            sub {require Net::FTP},
                            sub {require Net::Config},
                           ],
               'IO::Socket::SSL' => [
                                 sub {
                                     require IO::Socket::SSL;
                                     unless (CPAN::Version->vge(IO::Socket::SSL::->VERSION,1.56)) {
                                         for ("Will not use IO::Socket::SSL, need 1.56\n") {
                                             $CPAN::Frontend->mywarn($_);
                                             die $_;
                                         }
                                     }
                                 }
                                ],
               'Net::SSLeay' => [
                                 sub {
                                     require Net::SSLeay;
                                     unless (CPAN::Version->vge(Net::SSLeay::->VERSION,1.49)) {
                                         for ("Will not use Net::SSLeay, need 1.49\n") {
                                             $CPAN::Frontend->mywarn($_);
                                             die $_;
                                         }
                                     }
                                 }
                                ],
               'HTTP::Tiny' => [
                            sub {
                                require HTTP::Tiny;
                                unless (CPAN::Version->vge(HTTP::Tiny->VERSION, 0.005)) {
                                    for ("Will not use HTTP::Tiny, need version 0.005\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],
               'File::HomeDir' => [
                                   sub {require File::HomeDir;
                                        unless (CPAN::Version->vge(File::HomeDir::->VERSION, 0.52)) {
                                            for ("Will not use File::HomeDir, need 0.52\n") {
                                                $CPAN::Frontend->mywarn($_);
                                                die $_;
                                            }
                                        }
                                    },
                                  ],
               'Archive::Tar' => [
                                  sub {require Archive::Tar;
                                       my $demand = "1.50";
                                       unless (CPAN::Version->vge(Archive::Tar::->VERSION, $demand)) {
                                            my $atv = Archive::Tar->VERSION;
                                            for ("You have Archive::Tar $atv, but $demand or later is recommended. Please upgrade.\n") {
                                                $CPAN::Frontend->mywarn($_);
                                            # don't die, because we may need
                                            # Archive::Tar to upgrade
                                            }

                                       }
                                  },
                                 ],
               'File::Temp' => [
                                # XXX we should probably delete from
                                # %INC too so we can load after we
                                # installed a new enough version --
                                # I'm not sure.
                                sub {require File::Temp;
                                     unless (CPAN::Version->vge(File::Temp::->VERSION,0.16)) {
                                         for ("Will not use File::Temp, need 0.16\n") {
                                                $CPAN::Frontend->mywarn($_);
                                                die $_;
                                         }
                                     }
                                },
                               ]
              };
    if ($usable->{$mod}) {
        local @INC = @INC;
        pop @INC if $INC[-1] eq '.';
        for my $c (0..$#{$usable->{$mod}}) {
            my $code = $usable->{$mod}[$c];
            my $ret = eval { &$code() };
            $ret = "" unless defined $ret;
            if ($@) {
                # warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
                return;
            }
        }
    }
    return $HAS_USABLE->{$mod} = 1;
}

sub frontend {
    shift;
    $CPAN::Frontend = shift if @_;
    $CPAN::Frontend;
}

sub use_inst {
    my ($self, $module) = @_;

    unless ($self->has_inst($module)) {
        $self->frontend->mydie("$module not installed, cannot continue");
    }
}

#-> sub CPAN::has_inst
sub has_inst {
    my($self,$mod,$message) = @_;
    Carp::croak("CPAN->has_inst() called without an argument")
        unless defined $mod;
    my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
        keys %{$CPAN::Config->{dontload_hash}||{}},
            @{$CPAN::Config->{dontload_list}||[]};
    if (defined $message && $message eq "no"  # as far as I remember only used by Nox
        ||
        $dont{$mod}
       ) {
      $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
      return 0;
    }
    local @INC = @INC;
    pop @INC if $INC[-1] eq '.';
    my $file = $mod;
    my $obj;
    $file =~ s|::|/|g;
    $file .= ".pm";
    if ($INC{$file}) {
        # checking %INC is wrong, because $INC{LWP} may be true
        # although $INC{"URI/URL.pm"} may have failed. But as
        # I really want to say "blah loaded OK", I have to somehow
        # cache results.
        ### warn "$file in %INC"; #debug
        return 1;
    } elsif (eval { require $file }) {
        # eval is good: if we haven't yet read the database it's
        # perfect and if we have installed the module in the meantime,
        # it tries again. The second require is only a NOOP returning
        # 1 if we had success, otherwise it's retrying

        my $mtime = (stat $INC{$file})[9];
        # privileged files loaded by has_inst; Note: we use $mtime
        # as a proxy for a checksum.
        $CPAN::Shell::reload->{$file} = $mtime;
        my $v = eval "\$$mod\::VERSION";
        $v = $v ? " (v$v)" : "";
        CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
        if ($mod eq "CPAN::WAIT") {
            push @CPAN::Shell::ISA, 'CPAN::WAIT';
        }
        return 1;
    } elsif ($mod eq "Net::FTP") {
        $CPAN::Frontend->mywarn(qq{
  Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
  if you just type
      install Bundle::libnet

}) unless $Have_warned->{"Net::FTP"}++;
        $CPAN::Frontend->mysleep(3);
    } elsif ($mod eq "Digest::SHA") {
        if ($Have_warned->{"Digest::SHA"}++) {
            $CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
                                     qq{because Digest::SHA not installed.\n});
        } else {
            $CPAN::Frontend->mywarn(qq{
  CPAN: checksum security checks disabled because Digest::SHA not installed.
  Please consider installing the Digest::SHA module.

});
            $CPAN::Frontend->mysleep(2);
        }
    } elsif ($mod eq "Module::Signature") {
        # NOT prefs_lookup, we are not a distro
        my $check_sigs = $CPAN::Config->{check_sigs};
        if (not $check_sigs) {
            # they do not want us:-(
        } elsif (not $Have_warned->{"Module::Signature"}++) {
            # No point in complaining unless the user can
            # reasonably install and use it.
            if (eval { require Crypt::OpenPGP; 1 } ||
                (
                 defined $CPAN::Config->{'gpg'}
                 &&
                 $CPAN::Config->{'gpg'} =~ /\S/
                )
               ) {
                $CPAN::Frontend->mywarn(qq{
  CPAN: Module::Signature security checks disabled because Module::Signature
  not installed.  Please consider installing the Module::Signature module.
  You may also need to be able to connect over the Internet to the public
  key servers like pool.sks-keyservers.net or pgp.mit.edu.

});
                $CPAN::Frontend->mysleep(2);
            }
        }
    } else {
        delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
    }
    return 0;
}

#-> sub CPAN::instance ;
sub instance {
    my($mgr,$class,$id) = @_;
    CPAN::Index->reload;
    $id ||= "";
    # unsafe meta access, ok?
    return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
    $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
}

#-> sub CPAN::new ;
sub new {
    bless {}, shift;
}

#-> sub CPAN::_exit_messages ;
sub _exit_messages {
    my ($self) = @_;
    $self->{exit_messages} ||= [];
}

#-> sub CPAN::cleanup ;
sub cleanup {
  # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
  local $SIG{__DIE__} = '';
  my($message) = @_;
  my $i = 0;
  my $ineval = 0;
  my($subroutine);
  while ((undef,undef,undef,$subroutine) = caller(++$i)) {
      $ineval = 1, last if
        $subroutine eq '(eval)';
  }
  return if $ineval && !$CPAN::End;
  return unless defined $META->{LOCK};
  return unless -f $META->{LOCK};
  $META->savehist;
  $META->{cachemgr} ||= CPAN::CacheMgr->new('atexit');
  close $META->{LOCKFH};
  unlink $META->{LOCK};
  # require Carp;
  # Carp::cluck("DEBUGGING");
  if ( $CPAN::CONFIG_DIRTY ) {
      $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
  }
  $CPAN::Frontend->myprint("Lockfile removed.\n");
  for my $msg ( @{ $META->_exit_messages } ) {
      $CPAN::Frontend->myprint($msg);
  }
}

#-> sub CPAN::readhist
sub readhist {
    my($self,$term,$histfile) = @_;
    my $histsize = $CPAN::Config->{'histsize'} || 100;
    $term->Attribs->{'MaxHistorySize'} = $histsize if (defined($term->Attribs->{'MaxHistorySize'}));
    my($fh) = FileHandle->new;
    open $fh, "<$histfile" or return;
    local $/ = "\n";
    while (<$fh>) {
        chomp;
        $term->AddHistory($_);
    }
    close $fh;
}

#-> sub CPAN::savehist
sub savehist {
    my($self) = @_;
    my($histfile,$histsize);
    unless ($histfile = $CPAN::Config->{'histfile'}) {
        $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
        return;
    }
    $histsize = $CPAN::Config->{'histsize'} || 100;
    if ($CPAN::term) {
        unless ($CPAN::term->can("GetHistory")) {
            $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
            return;
        }
    } else {
        return;
    }
    my @h = $CPAN::term->GetHistory;
    splice @h, 0, @h-$histsize if @h>$histsize;
    my($fh) = FileHandle->new;
    open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
    local $\ = local $, = "\n";
    print $fh @h;
    close $fh;
}

#-> sub CPAN::is_tested
sub is_tested {
    my($self,$what,$when) = @_;
    unless ($what) {
        Carp::cluck("DEBUG: empty what");
        return;
    }
    $self->{is_tested}{$what} = $when;
}

#-> sub CPAN::reset_tested
# forget all distributions tested -- resets what gets included in PERL5LIB
sub reset_tested {
    my ($self) = @_;
    $self->{is_tested} = {};
}

#-> sub CPAN::is_installed
# unsets the is_tested flag: as soon as the thing is installed, it is
# not needed in set_perl5lib anymore
sub is_installed {
    my($self,$what) = @_;
    delete $self->{is_tested}{$what};
}

sub _list_sorted_descending_is_tested {
    my($self) = @_;
    my $foul = 0;
    my @sorted = sort
        { ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
            grep
                { if ($foul){ 0 } elsif (-e) { 1 } else { $foul = $_; 0 } }
                    keys %{$self->{is_tested}};
    if ($foul) {
        $CPAN::Frontend->mywarn("Lost build_dir detected ($foul), giving up all cached test results of currently running session.\n");
        for my $dbd (sort keys %{$self->{is_tested}}) { # distro-build-dir
        SEARCH: for my $d (sort { $a->id cmp $b->id } $CPAN::META->all_objects("CPAN::Distribution")) {
                if ($d->{build_dir} && $d->{build_dir} eq $dbd) {
                    $CPAN::Frontend->mywarn(sprintf "Flushing cache for %s\n", $d->pretty_id);
                    $d->fforce("");
                    last SEARCH;
                }
            }
            delete $self->{is_tested}{$dbd};
        }
        return ();
    } else {
        return @sorted;
    }
}

#-> sub CPAN::set_perl5lib
# Notes on max environment variable length:
#   - Win32 : XP or later, 8191; Win2000 or NT4, 2047
{
my $fh;
sub set_perl5lib {
    my($self,$for) = @_;
    unless ($for) {
        (undef,undef,undef,$for) = caller(1);
        $for =~ s/.*://;
    }
    $self->{is_tested} ||= {};
    return unless %{$self->{is_tested}};
    my $env = $ENV{PERL5LIB};
    $env = $ENV{PERLLIB} unless defined $env;
    my @env;
    push @env, split /\Q$Config::Config{path_sep}\E/, $env if defined $env and length $env;
    #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
    #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");

    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
    return if !@dirs;

    if (@dirs < 12) {
        $CPAN::Frontend->optprint('perl5lib', "Prepending @dirs to PERL5LIB for '$for'\n");
        $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
    } elsif (@dirs < 24 ) {
        my @d = map {my $cp = $_;
                     $cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
                     $cp
                 } @dirs;
        $CPAN::Frontend->optprint('perl5lib', "Prepending @d to PERL5LIB; ".
                                 "%BUILDDIR%=$CPAN::Config->{build_dir} ".
                                 "for '$for'\n"
                                );
        $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
    } else {
        my $cnt = keys %{$self->{is_tested}};
        my $newenv = join $Config::Config{path_sep}, @dirs, @env;
        $CPAN::Frontend->optprint('perl5lib', sprintf ("Prepending blib/arch and blib/lib of ".
                                 "%d build dirs to PERL5LIB, reaching size %d; ".
                                 "for '%s'\n", $cnt, length($newenv), $for)
                                );
        $ENV{PERL5LIB} = $newenv;
    }
}}


1;


__END__

=head1 NAME

CPAN - query, download and build perl modules from CPAN sites

=head1 SYNOPSIS

Interactive mode:

  perl -MCPAN -e shell

--or--

  cpan

Basic commands:

  # Modules:

  cpan> install Acme::Meta                       # in the shell

  CPAN::Shell->install("Acme::Meta");            # in perl

  # Distributions:

  cpan> install NWCLARK/Acme-Meta-0.02.tar.gz    # in the shell

  CPAN::Shell->
    install("NWCLARK/Acme-Meta-0.02.tar.gz");    # in perl

  # module objects:

  $mo = CPAN::Shell->expandany($mod);
  $mo = CPAN::Shell->expand("Module",$mod);      # same thing

  # distribution objects:

  $do = CPAN::Shell->expand("Module",$mod)->distribution;
  $do = CPAN::Shell->expandany($distro);         # same thing
  $do = CPAN::Shell->expand("Distribution",
                            $distro);            # same thing

=head1 DESCRIPTION

The CPAN module automates or at least simplifies the make and install
of perl modules and extensions. It includes some primitive searching
capabilities and knows how to use LWP, HTTP::Tiny, Net::FTP and certain
external download clients to fetch distributions from the net.

These are fetched from one or more mirrored CPAN (Comprehensive
Perl Archive Network) sites and unpacked in a dedicated directory.

The CPAN module also supports named and versioned
I<bundles> of modules. Bundles simplify handling of sets of
related modules. See Bundles below.

The package contains a session manager and a cache manager. The
session manager keeps track of what has been fetched, built, and
installed in the current session. The cache manager keeps track of the
disk space occupied by the make processes and deletes excess space
using a simple FIFO mechanism.

All methods provided are accessible in a programmer style and in an
interactive shell style.

=head2 CPAN::shell([$prompt, $command]) Starting Interactive Mode

Enter interactive mode by running

    perl -MCPAN -e shell

or

    cpan

which puts you into a readline interface. If C<Term::ReadKey> and
either of C<Term::ReadLine::Perl> or C<Term::ReadLine::Gnu> are installed,
history and command completion are supported.

Once at the command line, type C<h> for one-page help
screen; the rest should be self-explanatory.

The function call C<shell> takes two optional arguments: one the
prompt, the second the default initial command line (the latter
only works if a real ReadLine interface module is installed).

The most common uses of the interactive modes are

=over 2

=item Searching for authors, bundles, distribution files and modules

There are corresponding one-letter commands C<a>, C<b>, C<d>, and C<m>
for each of the four categories and another, C<i> for any of the
mentioned four. Each of the four entities is implemented as a class
with slightly differing methods for displaying an object.

Arguments to these commands are either strings exactly matching
the identification string of an object, or regular expressions
matched case-insensitively against various attributes of the
objects. The parser only recognizes a regular expression when you
enclose it with slashes.

The principle is that the number of objects found influences how an
item is displayed. If the search finds one item, the result is
displayed with the rather verbose method C<as_string>, but if
more than one is found, each object is displayed with the terse method
C<as_glimpse>.

Examples:

  cpan> m Acme::MetaSyntactic
  Module id = Acme::MetaSyntactic
      CPAN_USERID  BOOK (Philippe Bruhat (BooK) <[...]>)
      CPAN_VERSION 0.99
      CPAN_FILE    B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
      UPLOAD_DATE  2006-11-06
      MANPAGE      Acme::MetaSyntactic - Themed metasyntactic variables names
      INST_FILE    /usr/local/lib/perl/5.10.0/Acme/MetaSyntactic.pm
      INST_VERSION 0.99
  cpan> a BOOK
  Author id = BOOK
      EMAIL        [...]
      FULLNAME     Philippe Bruhat (BooK)
  cpan> d BOOK/Acme-MetaSyntactic-0.99.tar.gz
  Distribution id = B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
      CPAN_USERID  BOOK (Philippe Bruhat (BooK) <[...]>)
      CONTAINSMODS Acme::MetaSyntactic Acme::MetaSyntactic::Alias [...]
      UPLOAD_DATE  2006-11-06
  cpan> m /lorem/
  Module  = Acme::MetaSyntactic::loremipsum (BOOK/Acme-MetaSyntactic-0.99.tar.gz)
  Module    Text::Lorem            (ADEOLA/Text-Lorem-0.3.tar.gz)
  Module    Text::Lorem::More      (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
  Module    Text::Lorem::More::Source (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
  cpan> i /berlin/
  Distribution    BEATNIK/Filter-NumberLines-0.02.tar.gz
  Module  = DateTime::TimeZone::Europe::Berlin (DROLSKY/DateTime-TimeZone-0.7904.tar.gz)
  Module    Filter::NumberLines    (BEATNIK/Filter-NumberLines-0.02.tar.gz)
  Author          [...]

The examples illustrate several aspects: the first three queries
target modules, authors, or distros directly and yield exactly one
result. The last two use regular expressions and yield several
results. The last one targets all of bundles, modules, authors, and
distros simultaneously. When more than one result is available, they
are printed in one-line format.

=item C<get>, C<make>, C<test>, C<install>, C<clean> modules or distributions

These commands take any number of arguments and investigate what is
necessary to perform the action. Argument processing is as follows:

  known module name in format Foo/Bar.pm   module
  other embedded slash                     distribution
    - with trailing slash dot              directory
  enclosing slashes                        regexp
  known module name in format Foo::Bar     module

If the argument is a distribution file name (recognized by embedded
slashes), it is processed. If it is a module, CPAN determines the
distribution file in which this module is included and processes that,
following any dependencies named in the module's META.yml or
Makefile.PL (this behavior is controlled by the configuration
parameter C<prerequisites_policy>). If an argument is enclosed in
slashes it is treated as a regular expression: it is expanded and if
the result is a single object (distribution, bundle or module), this
object is processed.

Example:

    install Dummy::Perl                   # installs the module
    install AUXXX/Dummy-Perl-3.14.tar.gz  # installs that distribution
    install /Dummy-Perl-3.14/             # same if the regexp is unambiguous

C<get> downloads a distribution file and untars or unzips it, C<make>
builds it, C<test> runs the test suite, and C<install> installs it.

Any C<make> or C<test> is run unconditionally. An

  install <distribution_file>

is also run unconditionally. But for

  install <module>

CPAN checks whether an install is needed and prints
I<module up to date> if the distribution file containing
the module doesn't need updating.

CPAN also keeps track of what it has done within the current session
and doesn't try to build a package a second time regardless of whether it
succeeded or not. It does not repeat a test run if the test
has been run successfully before. Same for install runs.

The C<force> pragma may precede another command (currently: C<get>,
C<make>, C<test>, or C<install>) to execute the command from scratch
and attempt to continue past certain errors. See the section below on
the C<force> and the C<fforce> pragma.

The C<notest> pragma skips the test part in the build
process.

Example:

    cpan> notest install Tk

A C<clean> command results in a

  make clean

being executed within the distribution file's working directory.

=item C<readme>, C<perldoc>, C<look> module or distribution

C<readme> displays the README file of the associated distribution.
C<Look> gets and untars (if not yet done) the distribution file,
changes to the appropriate directory and opens a subshell process in
that directory. C<perldoc> displays the module's pod documentation
in html or plain text format.

=item C<ls> author

=item C<ls> globbing_expression

The first form lists all distribution files in and below an author's
CPAN directory as stored in the CHECKSUMS files distributed on
CPAN. The listing recurses into subdirectories.

The second form limits or expands the output with shell
globbing as in the following examples:

      ls JV/make*
      ls GSAR/*make*
      ls */*make*

The last example is very slow and outputs extra progress indicators
that break the alignment of the result.

Note that globbing only lists directories explicitly asked for, for
example FOO/* will not list FOO/bar/Acme-Sthg-n.nn.tar.gz. This may be
regarded as a bug that may be changed in some future version.

=item C<failed>

The C<failed> command reports all distributions that failed on one of
C<make>, C<test> or C<install> for some reason in the currently
running shell session.

=item Persistence between sessions

If the C<YAML> or the C<YAML::Syck> module is installed a record of
the internal state of all modules is written to disk after each step.
The files contain a signature of the currently running perl version
for later perusal.

If the configurations variable C<build_dir_reuse> is set to a true
value, then CPAN.pm reads the collected YAML files. If the stored
signature matches the currently running perl, the stored state is
loaded into memory such that persistence between sessions
is effectively established.

=item The C<force> and the C<fforce> pragma

To speed things up in complex installation scenarios, CPAN.pm keeps
track of what it has already done and refuses to do some things a
second time. A C<get>, a C<make>, and an C<install> are not repeated.
A C<test> is repeated only if the previous test was unsuccessful. The
diagnostic message when CPAN.pm refuses to do something a second time
is one of I<Has already been >C<unwrapped|made|tested successfully> or
something similar. Another situation where CPAN refuses to act is an
C<install> if the corresponding C<test> was not successful.

In all these cases, the user can override this stubborn behaviour by
prepending the command with the word force, for example:

  cpan> force get Foo
  cpan> force make AUTHOR/Bar-3.14.tar.gz
  cpan> force test Baz
  cpan> force install Acme::Meta

Each I<forced> command is executed with the corresponding part of its
memory erased.

The C<fforce> pragma is a variant that emulates a C<force get> which
erases the entire memory followed by the action specified, effectively
restarting the whole get/make/test/install procedure from scratch.

=item Lockfile

Interactive sessions maintain a lockfile, by default C<~/.cpan/.lock>.
Batch jobs can run without a lockfile and not disturb each other.

The shell offers to run in I<downgraded mode> when another process is
holding the lockfile. This is an experimental feature that is not yet
tested very well. This second shell then does not write the history
file, does not use the metadata file, and has a different prompt.

=item Signals

CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
in the cpan-shell, it is intended that you can press C<^C> anytime and
return to the cpan-shell prompt. A SIGTERM will cause the cpan-shell
to clean up and leave the shell loop. You can emulate the effect of a
SIGTERM by sending two consecutive SIGINTs, which usually means by
pressing C<^C> twice.

CPAN.pm ignores SIGPIPE. If the user sets C<inactivity_timeout>, a
SIGALRM is used during the run of the C<perl Makefile.PL> or C<perl
Build.PL> subprocess. A SIGALRM is also used during module version
parsing, and is controlled by C<version_timeout>.

=back

=head2 CPAN::Shell

The commands available in the shell interface are methods in
the package CPAN::Shell. If you enter the shell command, your
input is split by the Text::ParseWords::shellwords() routine, which
acts like most shells do. The first word is interpreted as the
method to be invoked, and the rest of the words are treated as the method's arguments.
Continuation lines are supported by ending a line with a
literal backslash.

=head2 autobundle

C<autobundle> writes a bundle file into the
C<$CPAN::Config-E<gt>{cpan_home}/Bundle> directory. The file contains
a list of all modules that are both available from CPAN and currently
installed within @INC. Duplicates of each distribution are suppressed.
The name of the bundle file is based on the current date and a
counter, e.g. F<Bundle/Snapshot_2012_05_21_00.pm>. This is installed
again by running C<cpan Bundle::Snapshot_2012_05_21_00>, or installing
C<Bundle::Snapshot_2012_05_21_00> from the CPAN shell.

Return value: path to the written file.

=head2 hosts

Note: this feature is still in alpha state and may change in future
versions of CPAN.pm

This commands provides a statistical overview over recent download
activities. The data for this is collected in the YAML file
C<FTPstats.yml> in your C<cpan_home> directory. If no YAML module is
configured or YAML not installed, no stats are provided.

=over

=item install_tested

Install all distributions that have been tested successfully but have
not yet been installed. See also C<is_tested>.

=item is_tested

List all build directories of distributions that have been tested
successfully but have not yet been installed. See also
C<install_tested>.

=back

=head2 mkmyconfig

mkmyconfig() writes your own CPAN::MyConfig file into your C<~/.cpan/>
directory so that you can save your own preferences instead of the
system-wide ones.

=head2 r [Module|/Regexp/]...

scans current perl installation for modules that have a newer version
available on CPAN and provides a list of them. If called without
argument, all potential upgrades are listed; if called with arguments
the list is filtered to the modules and regexps given as arguments.

The listing looks something like this:

  Package namespace         installed    latest  in CPAN file
  CPAN                        1.94_64    1.9600  ANDK/CPAN-1.9600.tar.gz
  CPAN::Reporter               1.1801    1.1902  DAGOLDEN/CPAN-Reporter-1.1902.tar.gz
  YAML                           0.70      0.73  INGY/YAML-0.73.tar.gz
  YAML::Syck                     1.14      1.17  AVAR/YAML-Syck-1.17.tar.gz
  YAML::Tiny                     1.44      1.50  ADAMK/YAML-Tiny-1.50.tar.gz
  CGI                            3.43      3.55  MARKSTOS/CGI.pm-3.55.tar.gz
  Module::Build::YAML            1.40      1.41  DAGOLDEN/Module-Build-0.3800.tar.gz
  TAP::Parser::Result::YAML      3.22      3.23  ANDYA/Test-Harness-3.23.tar.gz
  YAML::XS                       0.34      0.35  INGY/YAML-LibYAML-0.35.tar.gz

It suppresses duplicates in the column C<in CPAN file> such that
distributions with many upgradeable modules are listed only once.

Note that the list is not sorted.

=head2 recent ***EXPERIMENTAL COMMAND***

The C<recent> command downloads a list of recent uploads to CPAN and
displays them I<slowly>. While the command is running, a $SIG{INT}
exits the loop after displaying the current item.

B<Note>: This command requires XML::LibXML installed.

B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.

B<Note>: See also L<smoke>

=head2 recompile

recompile() is a special command that takes no argument and
runs the make/test/install cycle with brute force over all installed
dynamically loadable extensions (a.k.a. XS modules) with 'force' in
effect. The primary purpose of this command is to finish a network
installation. Imagine you have a common source tree for two different
architectures. You decide to do a completely independent fresh
installation. You start on one architecture with the help of a Bundle
file produced earlier. CPAN installs the whole Bundle for you, but
when you try to repeat the job on the second architecture, CPAN
responds with a C<"Foo up to date"> message for all modules. So you
invoke CPAN's recompile on the second architecture and you're done.

Another popular use for C<recompile> is to act as a rescue in case your
perl breaks binary compatibility. If one of the modules that CPAN uses
is in turn depending on binary compatibility (so you cannot run CPAN
commands), then you should try the CPAN::Nox module for recovery.

=head2 report Bundle|Distribution|Module

The C<report> command temporarily turns on the C<test_report> config
variable, then runs the C<force test> command with the given
arguments. The C<force> pragma reruns the tests and repeats
every step that might have failed before.

=head2 smoke ***EXPERIMENTAL COMMAND***

B<*** WARNING: this command downloads and executes software from CPAN to
your computer of completely unknown status. You should never do
this with your normal account and better have a dedicated well
separated and secured machine to do this. ***>

The C<smoke> command takes the list of recent uploads to CPAN as
provided by the C<recent> command and tests them all. While the
command is running $SIG{INT} is defined to mean that the current item
shall be skipped.

B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.

B<Note>: See also L<recent>

=head2 upgrade [Module|/Regexp/]...

The C<upgrade> command first runs an C<r> command with the given
arguments and then installs the newest versions of all modules that
were listed by that.

=head2 The four C<CPAN::*> Classes: Author, Bundle, Module, Distribution

Although it may be considered internal, the class hierarchy does matter
for both users and programmer. CPAN.pm deals with the four
classes mentioned above, and those classes all share a set of methods. Classical
single polymorphism is in effect. A metaclass object registers all
objects of all kinds and indexes them with a string. The strings
referencing objects have a separated namespace (well, not completely
separated):

         Namespace                         Class

   words containing a "/" (slash)      Distribution
    words starting with Bundle::          Bundle
          everything else            Module or Author

Modules know their associated Distribution objects. They always refer
to the most recent official release. Developers may mark their releases
as unstable development versions (by inserting an underscore into the
module version number which will also be reflected in the distribution
name when you run 'make dist'), so the really hottest and newest
distribution is not always the default.  If a module Foo circulates
on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
way to install version 1.23 by saying

    install Foo

This would install the complete distribution file (say
BAR/Foo-1.23.tar.gz) with all accompanying material. But if you would
like to install version 1.23_90, you need to know where the
distribution file resides on CPAN relative to the authors/id/
directory. If the author is BAR, this might be BAR/Foo-1.23_90.tar.gz;
so you would have to say

    install BAR/Foo-1.23_90.tar.gz

The first example will be driven by an object of the class
CPAN::Module, the second by an object of class CPAN::Distribution.

=head2 Integrating local directories

Note: this feature is still in alpha state and may change in future
versions of CPAN.pm

Distribution objects are normally distributions from the CPAN, but
there is a slightly degenerate case for Distribution objects, too, of
projects held on the local disk. These distribution objects have the
same name as the local directory and end with a dot. A dot by itself
is also allowed for the current directory at the time CPAN.pm was
used. All actions such as C<make>, C<test>, and C<install> are applied
directly to that directory. This gives the command C<cpan .> an
interesting touch: while the normal mantra of installing a CPAN module
without CPAN.pm is one of

    perl Makefile.PL                 perl Build.PL
           ( go and get prerequisites )
    make                             ./Build
    make test                        ./Build test
    make install                     ./Build install

the command C<cpan .> does all of this at once. It figures out which
of the two mantras is appropriate, fetches and installs all
prerequisites, takes care of them recursively, and finally finishes the
installation of the module in the current directory, be it a CPAN
module or not.

The typical usage case is for private modules or working copies of
projects from remote repositories on the local disk.

=head2 Redirection

The usual shell redirection symbols C< | > and C<< > >> are recognized
by the cpan shell B<only when surrounded by whitespace>. So piping to
pager or redirecting output into a file works somewhat as in a normal
shell, with the stipulation that you must type extra spaces.

=head2 Plugin support ***EXPERIMENTAL***

Plugins are objects that implement any of currently eight methods:

  pre_get
  post_get
  pre_make
  post_make
  pre_test
  post_test
  pre_install
  post_install

The C<plugin_list> configuration parameter holds a list of strings of
the form

  Modulename=arg0,arg1,arg2,arg3,...

eg:

  CPAN::Plugin::Flurb=dir,/opt/pkgs/flurb/raw,verbose,1

At run time, each listed plugin is instantiated as a singleton object
by running the equivalent of this pseudo code:

  my $plugin = <string representation from config>;
  <generate Modulename and arguments from $plugin>;
  my $p = $instance{$plugin} ||= Modulename->new($arg0,$arg1,...);

The generated singletons are kept around from instantiation until the
end of the shell session. <plugin_list> can be reconfigured at any
time at run time. While the cpan shell is running, it checks all
activated plugins at each of the 8 reference points listed above and
runs the respective method if it is implemented for that object. The
method is called with the active CPAN::Distribution object passed in
as an argument.

=head1 CONFIGURATION

When the CPAN module is used for the first time, a configuration
dialogue tries to determine a couple of site specific options. The
result of the dialog is stored in a hash reference C< $CPAN::Config >
in a file CPAN/Config.pm.

Default values defined in the CPAN/Config.pm file can be
overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
best placed in C<$HOME/.cpan/CPAN/MyConfig.pm>, because C<$HOME/.cpan> is
added to the search path of the CPAN module before the use() or
require() statements. The mkmyconfig command writes this file for you.

The C<o conf> command has various bells and whistles:

=over

=item completion support

If you have a ReadLine module installed, you can hit TAB at any point
of the commandline and C<o conf> will offer you completion for the
built-in subcommands and/or config variable names.

=item displaying some help: o conf help

Displays a short help

=item displaying current values: o conf [KEY]

Displays the current value(s) for this config variable. Without KEY,
displays all subcommands and config variables.

Example:

  o conf shell

If KEY starts and ends with a slash, the string in between is
treated as a regular expression and only keys matching this regexp
are displayed

Example:

  o conf /color/

=item changing of scalar values: o conf KEY VALUE

Sets the config variable KEY to VALUE. The empty string can be
specified as usual in shells, with C<''> or C<"">

Example:

  o conf wget /usr/bin/wget

=item changing of list values: o conf KEY SHIFT|UNSHIFT|PUSH|POP|SPLICE|LIST

If a config variable name ends with C<list>, it is a list. C<o conf
KEY shift> removes the first element of the list, C<o conf KEY pop>
removes the last element of the list. C<o conf KEYS unshift LIST>
prepends a list of values to the list, C<o conf KEYS push LIST>
appends a list of valued to the list.

Likewise, C<o conf KEY splice LIST> passes the LIST to the corresponding
splice command.

Finally, any other list of arguments is taken as a new list value for
the KEY variable discarding the previous value.

Examples:

  o conf urllist unshift http://cpan.dev.local/CPAN
  o conf urllist splice 3 1
  o conf urllist http://cpan1.local http://cpan2.local ftp://ftp.perl.org

=item reverting to saved: o conf defaults

Reverts all config variables to the state in the saved config file.

=item saving the config: o conf commit

Saves all config variables to the current config file (CPAN/Config.pm
or CPAN/MyConfig.pm that was loaded at start).

=back

The configuration dialog can be started any time later again by
issuing the command C< o conf init > in the CPAN shell. A subset of
the configuration dialog can be run by issuing C<o conf init WORD>
where WORD is any valid config variable or a regular expression.

=head2 Config Variables

The following keys in the hash reference $CPAN::Config are
currently defined:

  allow_installing_module_downgrades
                     allow or disallow installing module downgrades
  allow_installing_outdated_dists
                     allow or disallow installing modules that are
                     indexed in the cpan index pointing to a distro
                     with a higher distro-version number
  applypatch         path to external prg
  auto_commit        commit all changes to config variables to disk
  build_cache        size of cache for directories to build modules
  build_dir          locally accessible directory to build modules
  build_dir_reuse    boolean if distros in build_dir are persistent
  build_requires_install_policy
                     to install or not to install when a module is
                     only needed for building. yes|no|ask/yes|ask/no
  bzip2              path to external prg
  cache_metadata     use serializer to cache metadata
  check_sigs         if signatures should be verified
  cleanup_after_install
                     remove build directory immediately after a
                     successful install and remember that for the
                     duration of the session
  colorize_debug     Term::ANSIColor attributes for debugging output
  colorize_output    boolean if Term::ANSIColor should colorize output
  colorize_print     Term::ANSIColor attributes for normal output
  colorize_warn      Term::ANSIColor attributes for warnings
  commandnumber_in_prompt
                     boolean if you want to see current command number
  commands_quote     preferred character to use for quoting external
                     commands when running them. Defaults to double
                     quote on Windows, single tick everywhere else;
                     can be set to space to disable quoting
  connect_to_internet_ok
                     whether to ask if opening a connection is ok before
                     urllist is specified
  cpan_home          local directory reserved for this package
  curl               path to external prg
  dontload_hash      DEPRECATED
  dontload_list      arrayref: modules in the list will not be
                     loaded by the CPAN::has_inst() routine
  ftp                path to external prg
  ftp_passive        if set, the environment variable FTP_PASSIVE is set
                     for downloads
  ftp_proxy          proxy host for ftp requests
  ftpstats_period    max number of days to keep download statistics
  ftpstats_size      max number of items to keep in the download statistics
  getcwd             see below
  gpg                path to external prg
  gzip               location of external program gzip
  halt_on_failure    stop processing after the first failure of queued
                     items or dependencies
  histfile           file to maintain history between sessions
  histsize           maximum number of lines to keep in histfile
  http_proxy         proxy host for http requests
  inactivity_timeout breaks interactive Makefile.PLs or Build.PLs
                     after this many seconds inactivity. Set to 0 to
                     disable timeouts.
  index_expire       refetch index files after this many days
  inhibit_startup_message
                     if true, suppress the startup message
  keep_source_where  directory in which to keep the source (if we do)
  load_module_verbosity
                     report loading of optional modules used by CPAN.pm
  lynx               path to external prg
  make               location of external make program
  make_arg           arguments that should always be passed to 'make'
  make_install_make_command
                     the make command for running 'make install', for
                     example 'sudo make'
  make_install_arg   same as make_arg for 'make install'
  makepl_arg         arguments passed to 'perl Makefile.PL'
  mbuild_arg         arguments passed to './Build'
  mbuild_install_arg arguments passed to './Build install'
  mbuild_install_build_command
                     command to use instead of './Build' when we are
                     in the install stage, for example 'sudo ./Build'
  mbuildpl_arg       arguments passed to 'perl Build.PL'
  ncftp              path to external prg
  ncftpget           path to external prg
  no_proxy           don't proxy to these hosts/domains (comma separated list)
  pager              location of external program more (or any pager)
  password           your password if you CPAN server wants one
  patch              path to external prg
  patches_dir        local directory containing patch files
  perl5lib_verbosity verbosity level for PERL5LIB additions
  plugin_list        list of active hooks (see Plugin support above
                     and the CPAN::Plugin module)
  prefer_external_tar
                     per default all untar operations are done with
                     Archive::Tar; by setting this variable to true
                     the external tar command is used if available
  prefer_installer   legal values are MB and EUMM: if a module comes
                     with both a Makefile.PL and a Build.PL, use the
                     former (EUMM) or the latter (MB); if the module
                     comes with only one of the two, that one will be
                     used no matter the setting
  prerequisites_policy
                     what to do if you are missing module prerequisites
                     ('follow' automatically, 'ask' me, or 'ignore')
                     For 'follow', also sets PERL_AUTOINSTALL and
                     PERL_EXTUTILS_AUTOINSTALL for "--defaultdeps" if
                     not already set
  prefs_dir          local directory to store per-distro build options
  proxy_user         username for accessing an authenticating proxy
  proxy_pass         password for accessing an authenticating proxy
  pushy_https        use https to cpan.org when possible, otherwise use http
                     to cpan.org and issue a warning
  randomize_urllist  add some randomness to the sequence of the urllist
  recommends_policy  whether recommended prerequisites should be included
  scan_cache         controls scanning of cache ('atstart', 'atexit' or 'never')
  shell              your favorite shell
  show_unparsable_versions
                     boolean if r command tells which modules are versionless
  show_upload_date   boolean if commands should try to determine upload date
  show_zero_versions boolean if r command tells for which modules $version==0
  suggests_policy    whether suggested prerequisites should be included
  tar                location of external program tar
  tar_verbosity      verbosity level for the tar command
  term_is_latin      deprecated: if true Unicode is translated to ISO-8859-1
                     (and nonsense for characters outside latin range)
  term_ornaments     boolean to turn ReadLine ornamenting on/off
  test_report        email test reports (if CPAN::Reporter is installed)
  trust_test_report_history
                     skip testing when previously tested ok (according to
                     CPAN::Reporter history)
  unzip              location of external program unzip
  urllist            arrayref to nearby CPAN sites (or equivalent locations)
  urllist_ping_external
                     use external ping command when autoselecting mirrors
  urllist_ping_verbose
                     increase verbosity when autoselecting mirrors
  use_prompt_default set PERL_MM_USE_DEFAULT for configure/make/test/install
  use_sqlite         use CPAN::SQLite for metadata storage (fast and lean)
  username           your username if you CPAN server wants one
  version_timeout    stops version parsing after this many seconds.
                     Default is 15 secs. Set to 0 to disable.
  wait_list          arrayref to a wait server to try (See CPAN::WAIT)
  wget               path to external prg
  yaml_load_code     enable YAML code deserialisation via CPAN::DeferredCode
  yaml_module        which module to use to read/write YAML files

You can set and query each of these options interactively in the cpan
shell with the C<o conf> or the C<o conf init> command as specified below.

=over 2

=item C<o conf E<lt>scalar optionE<gt>>

prints the current value of the I<scalar option>

=item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>

Sets the value of the I<scalar option> to I<value>

=item C<o conf E<lt>list optionE<gt>>

prints the current value of the I<list option> in MakeMaker's
neatvalue format.

=item C<o conf E<lt>list optionE<gt> [shift|pop]>

shifts or pops the array in the I<list option> variable

=item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>

works like the corresponding perl commands.

=item interactive editing: o conf init [MATCH|LIST]

Runs an interactive configuration dialog for matching variables.
Without argument runs the dialog over all supported config variables.
To specify a MATCH the argument must be enclosed by slashes.

Examples:

  o conf init ftp_passive ftp_proxy
  o conf init /color/

Note: this method of setting config variables often provides more
explanation about the functioning of a variable than the manpage.

=back

=head2 CPAN::anycwd($path): Note on config variable getcwd

CPAN.pm changes the current working directory often and needs to
determine its own current working directory. By default it uses
Cwd::cwd, but if for some reason this doesn't work on your system,
configure alternatives according to the following table:

=over 4

=item cwd

Calls Cwd::cwd

=item getcwd

Calls Cwd::getcwd

=item fastcwd

Calls Cwd::fastcwd

=item getdcwd

Calls Cwd::getdcwd

=item backtickcwd

Calls the external command cwd.

=back

=head2 Note on the format of the urllist parameter

urllist parameters are URLs according to RFC 1738. We do a little
guessing if your URL is not compliant, but if you have problems with
C<file> URLs, please try the correct format. Either:

    file://localhost/whatever/ftp/pub/CPAN/

or

    file:///home/ftp/pub/CPAN/

=head2 The urllist parameter has CD-ROM support

The C<urllist> parameter of the configuration table contains a list of
URLs used for downloading. If the list contains any
C<file> URLs, CPAN always tries there first. This
feature is disabled for index files. So the recommendation for the
owner of a CD-ROM with CPAN contents is: include your local, possibly
outdated CD-ROM as a C<file> URL at the end of urllist, e.g.

  o conf urllist push file://localhost/CDROM/CPAN

CPAN.pm will then fetch the index files from one of the CPAN sites
that come at the beginning of urllist. It will later check for each
module to see whether there is a local copy of the most recent version.

Another peculiarity of urllist is that the site that we could
successfully fetch the last file from automatically gets a preference
token and is tried as the first site for the next request. So if you
add a new site at runtime it may happen that the previously preferred
site will be tried another time. This means that if you want to disallow
a site for the next transfer, it must be explicitly removed from
urllist.

=head2 Maintaining the urllist parameter

If you have YAML.pm (or some other YAML module configured in
C<yaml_module>) installed, CPAN.pm collects a few statistical data
about recent downloads. You can view the statistics with the C<hosts>
command or inspect them directly by looking into the C<FTPstats.yml>
file in your C<cpan_home> directory.

To get some interesting statistics, it is recommended that
C<randomize_urllist> be set; this introduces some amount of
randomness into the URL selection.

=head2 The C<requires> and C<build_requires> dependency declarations

Since CPAN.pm version 1.88_51 modules declared as C<build_requires> by
a distribution are treated differently depending on the config
variable C<build_requires_install_policy>. By setting
C<build_requires_install_policy> to C<no>, such a module is not
installed. It is only built and tested, and then kept in the list of
tested but uninstalled modules. As such, it is available during the
build of the dependent module by integrating the path to the
C<blib/arch> and C<blib/lib> directories in the environment variable
PERL5LIB. If C<build_requires_install_policy> is set to C<yes>, then
both modules declared as C<requires> and those declared as
C<build_requires> are treated alike. By setting to C<ask/yes> or
C<ask/no>, CPAN.pm asks the user and sets the default accordingly.

=head2 Configuration of the allow_installing_* parameters

The C<allow_installing_*> parameters are evaluated during
the C<make> phase. If set to C<yes>, they allow the testing and the installation of
the current distro and otherwise have no effect. If set to C<no>, they
may abort the build (preventing testing and installing), depending on the contents of the
C<blib/> directory. The C<blib/> directory is the directory that holds
all the files that would usually be installed in the C<install> phase.

C<allow_installing_outdated_dists> compares the C<blib/> directory with the CPAN index.
If it finds something there that belongs, according to the index, to a different
dist, it aborts the current build.

C<allow_installing_module_downgrades> compares the C<blib/> directory
with already installed modules, actually their version numbers, as
determined by ExtUtils::MakeMaker or equivalent. If a to-be-installed
module would downgrade an already installed module, the current build
is aborted.

An interesting twist occurs when a distroprefs document demands the
installation of an outdated dist via goto while
C<allow_installing_outdated_dists> forbids it. Without additional
provisions, this would let the C<allow_installing_outdated_dists>
win and the distroprefs lose. So the proper arrangement in such a case
is to write a second distroprefs document for the distro that C<goto>
points to and overrule the C<cpanconfig> there. E.g.:

  ---
  match:
    distribution: "^MAUKE/Keyword-Simple-0.04.tar.gz"
  goto: "MAUKE/Keyword-Simple-0.03.tar.gz"
  ---
  match:
    distribution: "^MAUKE/Keyword-Simple-0.03.tar.gz"
  cpanconfig:
    allow_installing_outdated_dists: yes

=head2 Configuration for individual distributions (I<Distroprefs>)

(B<Note:> This feature has been introduced in CPAN.pm 1.8854)

Distributions on CPAN usually behave according to what we call the
CPAN mantra. Or since the advent of Module::Build we should talk about
two mantras:

    perl Makefile.PL     perl Build.PL
    make                 ./Build
    make test            ./Build test
    make install         ./Build install

But some modules cannot be built with this mantra. They try to get
some extra data from the user via the environment, extra arguments, or
interactively--thus disturbing the installation of large bundles like
Phalanx100 or modules with many dependencies like Plagger.

The distroprefs system of C<CPAN.pm> addresses this problem by
allowing the user to specify extra informations and recipes in YAML
files to either

=over

=item

pass additional arguments to one of the four commands,

=item

set environment variables

=item

instantiate an Expect object that reads from the console, waits for
some regular expressions and enters some answers

=item

temporarily override assorted C<CPAN.pm> configuration variables

=item

specify dependencies the original maintainer forgot

=item

disable the installation of an object altogether

=back

See the YAML and Data::Dumper files that come with the C<CPAN.pm>
distribution in the C<distroprefs/> directory for examples.

=head2 Filenames

The YAML files themselves must have the C<.yml> extension; all other
files are ignored (for two exceptions see I<Fallback Data::Dumper and
Storable> below). The containing directory can be specified in
C<CPAN.pm> in the C<prefs_dir> config variable. Try C<o conf init
prefs_dir> in the CPAN shell to set and activate the distroprefs
system.

Every YAML file may contain arbitrary documents according to the YAML
specification, and every document is treated as an entity that
can specify the treatment of a single distribution.

Filenames can be picked arbitrarily; C<CPAN.pm> always reads
all files (in alphabetical order) and takes the key C<match> (see
below in I<Language Specs>) as a hashref containing match criteria
that determine if the current distribution matches the YAML document
or not.

=head2 Fallback Data::Dumper and Storable

If neither your configured C<yaml_module> nor YAML.pm is installed,
CPAN.pm falls back to using Data::Dumper and Storable and looks for
files with the extensions C<.dd> or C<.st> in the C<prefs_dir>
directory. These files are expected to contain one or more hashrefs.
For Data::Dumper generated files, this is expected to be done with by
defining C<$VAR1>, C<$VAR2>, etc. The YAML shell would produce these
with the command

    ysh < somefile.yml > somefile.dd

For Storable files the rule is that they must be constructed such that
C<Storable::retrieve(file)> returns an array reference and the array
elements represent one distropref object each. The conversion from
YAML would look like so:

    perl -MYAML=LoadFile -MStorable=nstore -e '
        @y=LoadFile(shift);
        nstore(\@y, shift)' somefile.yml somefile.st

In bootstrapping situations it is usually sufficient to translate only
a few YAML files to Data::Dumper for crucial modules like
C<YAML::Syck>, C<YAML.pm> and C<Expect.pm>. If you prefer Storable
over Data::Dumper, remember to pull out a Storable version that writes
an older format than all the other Storable versions that will need to
read them.

=head2 Blueprint

The following example contains all supported keywords and structures
with the exception of C<eexpect> which can be used instead of
C<expect>.

  ---
  comment: "Demo"
  match:
    module: "Dancing::Queen"
    distribution: "^CHACHACHA/Dancing-"
    not_distribution: "\.zip$"
    perl: "/usr/local/cariba-perl/bin/perl"
    perlconfig:
      archname: "freebsd"
      not_cc: "gcc"
    env:
      DANCING_FLOOR: "Shubiduh"
  disabled: 1
  cpanconfig:
    make: gmake
  pl:
    args:
      - "--somearg=specialcase"

    env: {}

    expect:
      - "Which is your favorite fruit"
      - "apple\n"

  make:
    args:
      - all
      - extra-all

    env: {}

    expect: []

    commandline: "echo SKIPPING make"

  test:
    args: []

    env: {}

    expect: []

  install:
    args: []

    env:
      WANT_TO_INSTALL: YES

    expect:
      - "Do you really want to install"
      - "y\n"

  patches:
    - "ABCDE/Fedcba-3.14-ABCDE-01.patch"

  depends:
    configure_requires:
      LWP: 5.8
    build_requires:
      Test::Exception: 0.25
    requires:
      Spiffy: 0.30


=head2 Language Specs

Every YAML document represents a single hash reference. The valid keys
in this hash are as follows:

=over

=item comment [scalar]

A comment

=item cpanconfig [hash]

Temporarily override assorted C<CPAN.pm> configuration variables.

Supported are: C<build_requires_install_policy>, C<check_sigs>,
C<make>, C<make_install_make_command>, C<prefer_installer>,
C<test_report>. Please report as a bug when you need another one
supported.

=item depends [hash] *** EXPERIMENTAL FEATURE ***

All three types, namely C<configure_requires>, C<build_requires>, and
C<requires> are supported in the way specified in the META.yml
specification. The current implementation I<merges> the specified
dependencies with those declared by the package maintainer. In a
future implementation this may be changed to override the original
declaration.

=item disabled [boolean]

Specifies that this distribution shall not be processed at all.

=item features [array] *** EXPERIMENTAL FEATURE ***

Experimental implementation to deal with optional_features from
META.yml. Still needs coordination with installer software and
currently works only for META.yml declaring C<dynamic_config=0>. Use
with caution.

=item goto [string]

The canonical name of a delegate distribution to install
instead. Useful when a new version, although it tests OK itself,
breaks something else or a developer release or a fork is already
uploaded that is better than the last released version.

=item install [hash]

Processing instructions for the C<make install> or C<./Build install>
phase of the CPAN mantra. See below under I<Processing Instructions>.

=item make [hash]

Processing instructions for the C<make> or C<./Build> phase of the
CPAN mantra. See below under I<Processing Instructions>.

=item match [hash]

A hashref with one or more of the keys C<distribution>, C<module>,
C<perl>, C<perlconfig>, and C<env> that specify whether a document is
targeted at a specific CPAN distribution or installation.
Keys prefixed with C<not_> negates the corresponding match.

The corresponding values are interpreted as regular expressions. The
C<distribution> related one will be matched against the canonical
distribution name, e.g. "AUTHOR/Foo-Bar-3.14.tar.gz".

The C<module> related one will be matched against I<all> modules
contained in the distribution until one module matches.

The C<perl> related one will be matched against C<$^X> (but with the
absolute path).

The value associated with C<perlconfig> is itself a hashref that is
matched against corresponding values in the C<%Config::Config> hash
living in the C<Config.pm> module.
Keys prefixed with C<not_> negates the corresponding match.

The value associated with C<env> is itself a hashref that is
matched against corresponding values in the C<%ENV> hash.
Keys prefixed with C<not_> negates the corresponding match.

If more than one restriction of C<module>, C<distribution>, etc. is
specified, the results of the separately computed match values must
all match. If so, the hashref represented by the
YAML document is returned as the preference structure for the current
distribution.

=item patches [array]

An array of patches on CPAN or on the local disk to be applied in
order via an external patch program. If the value for the C<-p>
parameter is C<0> or C<1> is determined by reading the patch
beforehand. The path to each patch is either an absolute path on the
local filesystem or relative to a patch directory specified in the
C<patches_dir> configuration variable or in the format of a canonical
distro name. For examples please consult the distroprefs/ directory in
the CPAN.pm distribution (these examples are not installed by
default).

Note: if the C<applypatch> program is installed and C<CPAN::Config>
knows about it B<and> a patch is written by the C<makepatch> program,
then C<CPAN.pm> lets C<applypatch> apply the patch. Both C<makepatch>
and C<applypatch> are available from CPAN in the C<JV/makepatch-*>
distribution.

=item pl [hash]

Processing instructions for the C<perl Makefile.PL> or C<perl
Build.PL> phase of the CPAN mantra. See below under I<Processing
Instructions>.

=item test [hash]

Processing instructions for the C<make test> or C<./Build test> phase
of the CPAN mantra. See below under I<Processing Instructions>.

=back

=head2 Processing Instructions

=over

=item args [array]

Arguments to be added to the command line

=item commandline

A full commandline to run via C<system()>.
During execution, the environment variable PERL is set
to $^X (but with an absolute path). If C<commandline> is specified,
C<args> is not used.

=item eexpect [hash]

Extended C<expect>. This is a hash reference with four allowed keys,
C<mode>, C<timeout>, C<reuse>, and C<talk>.

You must install the C<Expect> module to use C<eexpect>. CPAN.pm
does not install it for you.

C<mode> may have the values C<deterministic> for the case where all
questions come in the order written down and C<anyorder> for the case
where the questions may come in any order. The default mode is
C<deterministic>.

C<timeout> denotes a timeout in seconds. Floating-point timeouts are
OK. With C<mode=deterministic>, the timeout denotes the
timeout per question; with C<mode=anyorder> it denotes the
timeout per byte received from the stream or questions.

C<talk> is a reference to an array that contains alternating questions
and answers. Questions are regular expressions and answers are literal
strings. The Expect module watches the stream from the
execution of the external program (C<perl Makefile.PL>, C<perl
Build.PL>, C<make>, etc.).

For C<mode=deterministic>, the CPAN.pm injects the
corresponding answer as soon as the stream matches the regular expression.

For C<mode=anyorder> CPAN.pm answers a question as soon
as the timeout is reached for the next byte in the input stream. In
this mode you can use the C<reuse> parameter to decide what will
happen with a question-answer pair after it has been used. In the
default case (reuse=0) it is removed from the array, avoiding being
used again accidentally. If you want to answer the
question C<Do you really want to do that> several times, then it must
be included in the array at least as often as you want this answer to
be given. Setting the parameter C<reuse> to 1 makes this repetition
unnecessary.

=item env [hash]

Environment variables to be set during the command

=item expect [array]

You must install the C<Expect> module to use C<expect>. CPAN.pm
does not install it for you.

C<< expect: <array> >> is a short notation for this C<eexpect>:

	eexpect:
		mode: deterministic
		timeout: 15
		talk: <array>

=back

=head2 Schema verification with C<Kwalify>

If you have the C<Kwalify> module installed (which is part of the
Bundle::CPANxxl), then all your distroprefs files are checked for
syntactic correctness.

=head2 Example Distroprefs Files

C<CPAN.pm> comes with a collection of example YAML files. Note that these
are really just examples and should not be used without care because
they cannot fit everybody's purpose. After all, the authors of the
packages that ask questions had a need to ask, so you should watch
their questions and adjust the examples to your environment and your
needs. You have been warned:-)

=head1 PROGRAMMER'S INTERFACE

If you do not enter the shell, shell commands are
available both as methods (C<CPAN::Shell-E<gt>install(...)>) and as
functions in the calling package (C<install(...)>).  Before calling low-level
commands, it makes sense to initialize components of CPAN you need, e.g.:

  CPAN::HandleConfig->load;
  CPAN::Shell::setup_output;
  CPAN::Index->reload;

High-level commands do such initializations automatically.

There's currently only one class that has a stable interface -
CPAN::Shell. All commands that are available in the CPAN shell are
methods of the class CPAN::Shell. The arguments on the commandline are
passed as arguments to the method.

So if you take for example the shell command

  notest install A B C

the actually executed command is

  CPAN::Shell->notest("install","A","B","C");

Each of the commands that produce listings of modules (C<r>,
C<autobundle>, C<u>) also return a list of the IDs of all modules
within the list.

=over 2

=item expand($type,@things)

The IDs of all objects available within a program are strings that can
be expanded to the corresponding real objects with the
C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
list of CPAN::Module objects according to the C<@things> arguments
given. In scalar context, it returns only the first element of the
list.

=item expandany(@things)

Like expand, but returns objects of the appropriate type, i.e.
CPAN::Bundle objects for bundles, CPAN::Module objects for modules, and
CPAN::Distribution objects for distributions. Note: it does not expand
to CPAN::Author objects.

=item Programming Examples

This enables the programmer to do operations that combine
functionalities that are available in the shell.

    # install everything that is outdated on my disk:
    perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'

    # install my favorite programs if necessary:
    for $mod (qw(Net::FTP Digest::SHA Data::Dumper)) {
        CPAN::Shell->install($mod);
    }

    # list all modules on my disk that have no VERSION number
    for $mod (CPAN::Shell->expand("Module","/./")) {
        next unless $mod->inst_file;
        # MakeMaker convention for undefined $VERSION:
        next unless $mod->inst_version eq "undef";
        print "No VERSION in ", $mod->id, "\n";
    }

    # find out which distribution on CPAN contains a module:
    print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file

Or if you want to schedule a I<cron> job to watch CPAN, you could list
all modules that need updating. First a quick and dirty way:

    perl -e 'use CPAN; CPAN::Shell->r;'

If you don't want any output should all modules be
up to date, parse the output of above command for the regular
expression C</modules are up to date/> and decide to mail the output
only if it doesn't match.

If you prefer to do it more in a programmerish style in one single
process, something like this may better suit you:

  # list all modules on my disk that have newer versions on CPAN
  for $mod (CPAN::Shell->expand("Module","/./")) {
    next unless $mod->inst_file;
    next if $mod->uptodate;
    printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
        $mod->id, $mod->inst_version, $mod->cpan_version;
  }

If that gives too much output every day, you may want to
watch only for three modules. You can write

  for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")) {

as the first line instead. Or you can combine some of the above
tricks:

  # watch only for a new mod_perl module
  $mod = CPAN::Shell->expand("Module","mod_perl");
  exit if $mod->uptodate;
  # new mod_perl arrived, let me know all update recommendations
  CPAN::Shell->r;

=back

=head2 Methods in the other Classes

=over 4

=item CPAN::Author::as_glimpse()

Returns a one-line description of the author

=item CPAN::Author::as_string()

Returns a multi-line description of the author

=item CPAN::Author::email()

Returns the author's email address

=item CPAN::Author::fullname()

Returns the author's name

=item CPAN::Author::name()

An alias for fullname

=item CPAN::Bundle::as_glimpse()

Returns a one-line description of the bundle

=item CPAN::Bundle::as_string()

Returns a multi-line description of the bundle

=item CPAN::Bundle::clean()

Recursively runs the C<clean> method on all items contained in the bundle.

=item CPAN::Bundle::contains()

Returns a list of objects' IDs contained in a bundle. The associated
objects may be bundles, modules or distributions.

=item CPAN::Bundle::force($method,@args)

Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. The C<force> is passed recursively
to all contained objects. See also the section above on the C<force>
and the C<fforce> pragma.

=item CPAN::Bundle::get()

Recursively runs the C<get> method on all items contained in the bundle

=item CPAN::Bundle::inst_file()

Returns the highest installed version of the bundle in either @INC or
C<< $CPAN::Config->{cpan_home} >>. Note that this is different from
CPAN::Module::inst_file.

=item CPAN::Bundle::inst_version()

Like CPAN::Bundle::inst_file, but returns the $VERSION

=item CPAN::Bundle::uptodate()

Returns 1 if the bundle itself and all its members are up-to-date.

=item CPAN::Bundle::install()

Recursively runs the C<install> method on all items contained in the bundle

=item CPAN::Bundle::make()

Recursively runs the C<make> method on all items contained in the bundle

=item CPAN::Bundle::readme()

Recursively runs the C<readme> method on all items contained in the bundle

=item CPAN::Bundle::test()

Recursively runs the C<test> method on all items contained in the bundle

=item CPAN::Distribution::as_glimpse()

Returns a one-line description of the distribution

=item CPAN::Distribution::as_string()

Returns a multi-line description of the distribution

=item CPAN::Distribution::author

Returns the CPAN::Author object of the maintainer who uploaded this
distribution

=item CPAN::Distribution::pretty_id()

Returns a string of the form "AUTHORID/TARBALL", where AUTHORID is the
author's PAUSE ID and TARBALL is the distribution filename.

=item CPAN::Distribution::base_id()

Returns the distribution filename without any archive suffix.  E.g
"Foo-Bar-0.01"

=item CPAN::Distribution::clean()

Changes to the directory where the distribution has been unpacked and
runs C<make clean> there.

=item CPAN::Distribution::containsmods()

Returns a list of IDs of modules contained in a distribution file.
Works only for distributions listed in the 02packages.details.txt.gz
file. This typically means that just most recent version of a
distribution is covered.

=item CPAN::Distribution::cvs_import()

Changes to the directory where the distribution has been unpacked and
runs something like

    cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version

there.

=item CPAN::Distribution::dir()

Returns the directory into which this distribution has been unpacked.

=item CPAN::Distribution::force($method,@args)

Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.

=item CPAN::Distribution::get()

Downloads the distribution from CPAN and unpacks it. Does nothing if
the distribution has already been downloaded and unpacked within the
current session.

=item CPAN::Distribution::install()

Changes to the directory where the distribution has been unpacked and
runs the external command C<make install> there. If C<make> has not
yet been run, it will be run first. A C<make test> is issued in
any case and if this fails, the install is cancelled. The
cancellation can be avoided by letting C<force> run the C<install> for
you.

This install method only has the power to install the distribution if
there are no dependencies in the way. To install an object along with all
its dependencies, use CPAN::Shell->install.

Note that install() gives no meaningful return value. See uptodate().

=item CPAN::Distribution::isa_perl()

Returns 1 if this distribution file seems to be a perl distribution.
Normally this is derived from the file name only, but the index from
CPAN can contain a hint to achieve a return value of true for other
filenames too.

=item CPAN::Distribution::look()

Changes to the directory where the distribution has been unpacked and
opens a subshell there. Exiting the subshell returns.

=item CPAN::Distribution::make()

First runs the C<get> method to make sure the distribution is
downloaded and unpacked. Changes to the directory where the
distribution has been unpacked and runs the external commands C<perl
Makefile.PL> or C<perl Build.PL> and C<make> there.

=item CPAN::Distribution::perldoc()

Downloads the pod documentation of the file associated with a
distribution (in HTML format) and runs it through the external
command I<lynx> specified in C<< $CPAN::Config->{lynx} >>. If I<lynx>
isn't available, it converts it to plain text with the external
command I<html2text> and runs it through the pager specified
in C<< $CPAN::Config->{pager} >>.

=item CPAN::Distribution::prefs()

Returns the hash reference from the first matching YAML file that the
user has deposited in the C<prefs_dir/> directory. The first
succeeding match wins. The files in the C<prefs_dir/> are processed
alphabetically, and the canonical distro name (e.g.
AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
stored in the $root->{match}{distribution} attribute value.
Additionally all module names contained in a distribution are matched
against the regular expressions in the $root->{match}{module} attribute
value. The two match values are ANDed together. Each of the two
attributes are optional.

=item CPAN::Distribution::prereq_pm()

Returns the hash reference that has been announced by a distribution
as the C<requires> and C<build_requires> elements. These can be
declared either by the C<META.yml> (if authoritative) or can be
deposited after the run of C<Build.PL> in the file C<./_build/prereqs>
or after the run of C<Makfile.PL> written as the C<PREREQ_PM> hash in
a comment in the produced C<Makefile>. I<Note>: this method only works
after an attempt has been made to C<make> the distribution. Returns
undef otherwise.

=item CPAN::Distribution::readme()

Downloads the README file associated with a distribution and runs it
through the pager specified in C<< $CPAN::Config->{pager} >>.

=item CPAN::Distribution::reports()

Downloads report data for this distribution from www.cpantesters.org
and displays a subset of them.

=item CPAN::Distribution::read_yaml()

Returns the content of the META.yml of this distro as a hashref. Note:
works only after an attempt has been made to C<make> the distribution.
Returns undef otherwise. Also returns undef if the content of META.yml
is not authoritative. (The rules about what exactly makes the content
authoritative are still in flux.)

=item CPAN::Distribution::test()

Changes to the directory where the distribution has been unpacked and
runs C<make test> there.

=item CPAN::Distribution::uptodate()

Returns 1 if all the modules contained in the distribution are
up-to-date. Relies on containsmods.

=item CPAN::Index::force_reload()

Forces a reload of all indices.

=item CPAN::Index::reload()

Reloads all indices if they have not been read for more than
C<< $CPAN::Config->{index_expire} >> days.

=item CPAN::InfoObj::dump()

CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
inherit this method. It prints the data structure associated with an
object. Useful for debugging. Note: the data structure is considered
internal and thus subject to change without notice.

=item CPAN::Module::as_glimpse()

Returns a one-line description of the module in four columns: The
first column contains the word C<Module>, the second column consists
of one character: an equals sign if this module is already installed
and up-to-date, a less-than sign if this module is installed but can be
upgraded, and a space if the module is not installed. The third column
is the name of the module and the fourth column gives maintainer or
distribution information.

=item CPAN::Module::as_string()

Returns a multi-line description of the module

=item CPAN::Module::clean()

Runs a clean on the distribution associated with this module.

=item CPAN::Module::cpan_file()

Returns the filename on CPAN that is associated with the module.

=item CPAN::Module::cpan_version()

Returns the latest version of this module available on CPAN.

=item CPAN::Module::cvs_import()

Runs a cvs_import on the distribution associated with this module.

=item CPAN::Module::description()

Returns a 44 character description of this module. Only available for
modules listed in The Module List (CPAN/modules/00modlist.long.html
or 00modlist.long.txt.gz)

=item CPAN::Module::distribution()

Returns the CPAN::Distribution object that contains the current
version of this module.

=item CPAN::Module::dslip_status()

Returns a hash reference. The keys of the hash are the letters C<D>,
C<S>, C<L>, C<I>, and <P>, for development status, support level,
language, interface and public licence respectively. The data for the
DSLIP status are collected by pause.perl.org when authors register
their namespaces. The values of the 5 hash elements are one-character
words whose meaning is described in the table below. There are also 5
hash elements C<DV>, C<SV>, C<LV>, C<IV>, and <PV> that carry a more
verbose value of the 5 status variables.

Where the 'DSLIP' characters have the following meanings:

  D - Development Stage  (Note: *NO IMPLIED TIMESCALES*):
    i   - Idea, listed to gain consensus or as a placeholder
    c   - under construction but pre-alpha (not yet released)
    a/b - Alpha/Beta testing
    R   - Released
    M   - Mature (no rigorous definition)
    S   - Standard, supplied with Perl 5

  S - Support Level:
    m   - Mailing-list
    d   - Developer
    u   - Usenet newsgroup comp.lang.perl.modules
    n   - None known, try comp.lang.perl.modules
    a   - abandoned; volunteers welcome to take over maintenance

  L - Language Used:
    p   - Perl-only, no compiler needed, should be platform independent
    c   - C and perl, a C compiler will be needed
    h   - Hybrid, written in perl with optional C code, no compiler needed
    +   - C++ and perl, a C++ compiler will be needed
    o   - perl and another language other than C or C++

  I - Interface Style
    f   - plain Functions, no references used
    h   - hybrid, object and function interfaces available
    n   - no interface at all (huh?)
    r   - some use of unblessed References or ties
    O   - Object oriented using blessed references and/or inheritance

  P - Public License
    p   - Standard-Perl: user may choose between GPL and Artistic
    g   - GPL: GNU General Public License
    l   - LGPL: "GNU Lesser General Public License" (previously known as
          "GNU Library General Public License")
    b   - BSD: The BSD License
    a   - Artistic license alone
    2   - Artistic license 2.0 or later
    o   - open source: approved by www.opensource.org
    d   - allows distribution without restrictions
    r   - restricted distribution
    n   - no license at all

=item CPAN::Module::force($method,@args)

Forces CPAN to perform a task it would normally refuse to
do. Force takes as arguments a method name to be invoked and any number
of additional arguments to pass that method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.

=item CPAN::Module::get()

Runs a get on the distribution associated with this module.

=item CPAN::Module::inst_file()

Returns the filename of the module found in @INC. The first file found
is reported, just as perl itself stops searching @INC once it finds a
module.

=item CPAN::Module::available_file()

Returns the filename of the module found in PERL5LIB or @INC. The
first file found is reported. The advantage of this method over
C<inst_file> is that modules that have been tested but not yet
installed are included because PERL5LIB keeps track of tested modules.

=item CPAN::Module::inst_version()

Returns the version number of the installed module in readable format.

=item CPAN::Module::available_version()

Returns the version number of the available module in readable format.

=item CPAN::Module::install()

Runs an C<install> on the distribution associated with this module.

=item CPAN::Module::look()

Changes to the directory where the distribution associated with this
module has been unpacked and opens a subshell there. Exiting the
subshell returns.

=item CPAN::Module::make()

Runs a C<make> on the distribution associated with this module.

=item CPAN::Module::manpage_headline()

If module is installed, peeks into the module's manpage, reads the
headline, and returns it. Moreover, if the module has been downloaded
within this session, does the equivalent on the downloaded module even
if it hasn't been installed yet.

=item CPAN::Module::perldoc()

Runs a C<perldoc> on this module.

=item CPAN::Module::readme()

Runs a C<readme> on the distribution associated with this module.

=item CPAN::Module::reports()

Calls the reports() method on the associated distribution object.

=item CPAN::Module::test()

Runs a C<test> on the distribution associated with this module.

=item CPAN::Module::uptodate()

Returns 1 if the module is installed and up-to-date.

=item CPAN::Module::userid()

Returns the author's ID of the module.

=back

=head2 Cache Manager

Currently the cache manager only keeps track of the build directory
($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
deletes complete directories below C<build_dir> as soon as the size of
all directories there gets bigger than $CPAN::Config->{build_cache}
(in MB). The contents of this cache may be used for later
re-installations that you intend to do manually, but will never be
trusted by CPAN itself. This is due to the fact that the user might
use these directories for building modules on different architectures.

There is another directory ($CPAN::Config->{keep_source_where}) where
the original distribution files are kept. This directory is not
covered by the cache manager and must be controlled by the user. If
you choose to have the same directory as build_dir and as
keep_source_where directory, then your sources will be deleted with
the same fifo mechanism.

=head2 Bundles

A bundle is just a perl module in the namespace Bundle:: that does not
define any functions or methods. It usually only contains documentation.

It starts like a perl module with a package declaration and a $VERSION
variable. After that the pod section looks like any other pod with the
only difference being that I<one special pod section> exists starting with
(verbatim):

    =head1 CONTENTS

In this pod section each line obeys the format

        Module_Name [Version_String] [- optional text]

The only required part is the first field, the name of a module
(e.g. Foo::Bar, i.e. I<not> the name of the distribution file). The rest
of the line is optional. The comment part is delimited by a dash just
as in the man page header.

The distribution of a bundle should follow the same convention as
other distributions.

Bundles are treated specially in the CPAN package. If you say 'install
Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
the modules in the CONTENTS section of the pod. You can install your
own Bundles locally by placing a conformant Bundle file somewhere into
your @INC path. The autobundle() command which is available in the
shell interface does that for you by including all currently installed
modules in a snapshot bundle file.

=head1 PREREQUISITES

The CPAN program is trying to depend on as little as possible so the
user can use it in hostile environment. It works better the more goodies
the environment provides. For example if you try in the CPAN shell

  install Bundle::CPAN

or

  install Bundle::CPANxxl

you will find the shell more convenient than the bare shell before.

If you have a local mirror of CPAN and can access all files with
"file:" URLs, then you only need a perl later than perl5.003 to run
this module. Otherwise Net::FTP is strongly recommended. LWP may be
required for non-UNIX systems, or if your nearest CPAN site is
associated with a URL that is not C<ftp:>.

If you have neither Net::FTP nor LWP, there is a fallback mechanism
implemented for an external ftp command or for an external lynx
command.

=head1 UTILITIES

=head2 Finding packages and VERSION

This module presumes that all packages on CPAN

=over 2

=item *

declare their $VERSION variable in an easy to parse manner. This
prerequisite can hardly be relaxed because it consumes far too much
memory to load all packages into the running program just to determine
the $VERSION variable. Currently all programs that are dealing with
version use something like this

    perl -MExtUtils::MakeMaker -le \
        'print MM->parse_version(shift)' filename

If you are author of a package and wonder if your $VERSION can be
parsed, please try the above method.

=item *

come as compressed or gzipped tarfiles or as zip files and contain a
C<Makefile.PL> or C<Build.PL> (well, we try to handle a bit more, but
with little enthusiasm).

=back

=head2 Debugging

Debugging this module is more than a bit complex due to interference from
the software producing the indices on CPAN, the mirroring process on CPAN,
packaging, configuration, synchronicity, and even (gasp!) due to bugs
within the CPAN.pm module itself.

For debugging the code of CPAN.pm itself in interactive mode, some
debugging aid can be turned on for most packages within
CPAN.pm with one of

=over 2

=item o debug package...

sets debug mode for packages.

=item o debug -package...

unsets debug mode for packages.

=item o debug all

turns debugging on for all packages.

=item o debug number

=back

which sets the debugging packages directly. Note that C<o debug 0>
turns debugging off.

What seems a successful strategy is the combination of C<reload
cpan> and the debugging switches. Add a new debug statement while
running in the shell and then issue a C<reload cpan> and see the new
debugging messages immediately without losing the current context.

C<o debug> without an argument lists the valid package names and the
current set of packages in debugging mode. C<o debug> has built-in
completion support.

For debugging of CPAN data there is the C<dump> command which takes
the same arguments as make/test/install and outputs each object's
Data::Dumper dump. If an argument looks like a perl variable and
contains one of C<$>, C<@> or C<%>, it is eval()ed and fed to
Data::Dumper directly.

=head2 Floppy, Zip, Offline Mode

CPAN.pm works nicely without network access, too. If you maintain machines
that are not networked at all, you should consider working with C<file:>
URLs. You'll have to collect your modules somewhere first. So
you might use CPAN.pm to put together all you need on a networked
machine. Then copy the $CPAN::Config->{keep_source_where} (but not
$CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
of a personal CPAN. CPAN.pm on the non-networked machines works nicely
with this floppy. See also below the paragraph about CD-ROM support.

=head2 Basic Utilities for Programmers

=over 2

=item has_inst($module)

Returns true if the module is installed. Used to load all modules into
the running CPAN.pm that are considered optional. The config variable
C<dontload_list> intercepts the C<has_inst()> call such
that an optional module is not loaded despite being available. For
example, the following command will prevent C<YAML.pm> from being
loaded:

    cpan> o conf dontload_list push YAML

See the source for details.

=item use_inst($module)

Similary to L<has_inst()> tries to load optional library but also dies if
library is not available

=item has_usable($module)

Returns true if the module is installed and in a usable state. Only
useful for a handful of modules that are used internally. See the
source for details.

=item instance($module)

The constructor for all the singletons used to represent modules,
distributions, authors, and bundles. If the object already exists, this
method returns the object; otherwise, it calls the constructor.

=item frontend()

=item frontend($new_frontend)

Getter/setter for frontend object. Method just allows to subclass CPAN.pm.

=back

=head1 SECURITY

There's no strong security layer in CPAN.pm. CPAN.pm helps you to
install foreign, unmasked, unsigned code on your machine. We compare
to a checksum that comes from the net just as the distribution file
itself. But we try to make it easy to add security on demand:

=head2 Cryptographically signed modules

Since release 1.77, CPAN.pm has been able to verify cryptographically
signed module distributions using Module::Signature.  The CPAN modules
can be signed by their authors, thus giving more security.  The simple
unsigned MD5 checksums that were used before by CPAN protect mainly
against accidental file corruption.

You will need to have Module::Signature installed, which in turn
requires that you have at least one of Crypt::OpenPGP module or the
command-line F<gpg> tool installed.

You will also need to be able to connect over the Internet to the public
key servers, like pgp.mit.edu, and their port 11731 (the HKP protocol).

The configuration parameter check_sigs is there to turn signature
checking on or off.

=head1 EXPORT

Most functions in package CPAN are exported by default. The reason
for this is that the primary use is intended for the cpan shell or for
one-liners.

=head1 ENVIRONMENT

When the CPAN shell enters a subshell via the look command, it sets
the environment CPAN_SHELL_LEVEL to 1, or increments that variable if it is
already set.

When CPAN runs, it sets the environment variable PERL5_CPAN_IS_RUNNING
to the ID of the running process. It also sets
PERL5_CPANPLUS_IS_RUNNING to prevent runaway processes which could
happen with older versions of Module::Install.

When running C<perl Makefile.PL>, the environment variable
C<PERL5_CPAN_IS_EXECUTING> is set to the full path of the
C<Makefile.PL> that is being executed. This prevents runaway processes
with newer versions of Module::Install.

When the config variable ftp_passive is set, all downloads will be run
with the environment variable FTP_PASSIVE set to this value. This is
in general a good idea as it influences both Net::FTP and LWP based
connections. The same effect can be achieved by starting the cpan
shell with this environment variable set. For Net::FTP alone, one can
also always set passive mode by running libnetcfg.

=head1 POPULATE AN INSTALLATION WITH LOTS OF MODULES

Populating a freshly installed perl with one's favorite modules is pretty
easy if you maintain a private bundle definition file. To get a useful
blueprint of a bundle definition file, the command autobundle can be used
on the CPAN shell command line. This command writes a bundle definition
file for all modules installed for the current perl
interpreter. It's recommended to run this command once only, and from then
on maintain the file manually under a private name, say
Bundle/my_bundle.pm. With a clever bundle file you can then simply say

    cpan> install Bundle::my_bundle

then answer a few questions and go out for coffee (possibly
even in a different city).

Maintaining a bundle definition file means keeping track of two
things: dependencies and interactivity. CPAN.pm sometimes fails on
calculating dependencies because not all modules define all MakeMaker
attributes correctly, so a bundle definition file should specify
prerequisites as early as possible. On the other hand, it's
annoying that so many distributions need some interactive configuring. So
what you can try to accomplish in your private bundle file is to have the
packages that need to be configured early in the file and the gentle
ones later, so you can go out for coffee after a few minutes and leave CPAN.pm
to churn away unattended.

=head1 WORKING WITH CPAN.pm BEHIND FIREWALLS

Thanks to Graham Barr for contributing the following paragraphs about
the interaction between perl, and various firewall configurations. For
further information on firewalls, it is recommended to consult the
documentation that comes with the I<ncftp> program. If you are unable to
go through the firewall with a simple Perl setup, it is likely
that you can configure I<ncftp> so that it works through your firewall.

=head2 Three basic types of firewalls

Firewalls can be categorized into three basic types.

=over 4

=item http firewall

This is when the firewall machine runs a web server, and to access the
outside world, you must do so via that web server. If you set environment
variables like http_proxy or ftp_proxy to values beginning with http://,
or in your web browser you've proxy information set, then you know
you are running behind an http firewall.

To access servers outside these types of firewalls with perl (even for
ftp), you need LWP or HTTP::Tiny.

=item ftp firewall

This where the firewall machine runs an ftp server. This kind of
firewall will only let you access ftp servers outside the firewall.
This is usually done by connecting to the firewall with ftp, then
entering a username like "user@outside.host.com".

To access servers outside these type of firewalls with perl, you
need Net::FTP.

=item One-way visibility

One-way visibility means these firewalls try to make themselves
invisible to users inside the firewall. An FTP data connection is
normally created by sending your IP address to the remote server and then
listening for the return connection. But the remote server will not be able to
connect to you because of the firewall. For these types of firewall,
FTP connections need to be done in a passive mode.

There are two that I can think off.

=over 4

=item SOCKS

If you are using a SOCKS firewall, you will need to compile perl and link
it with the SOCKS library.  This is what is normally called a 'socksified'
perl. With this executable you will be able to connect to servers outside
the firewall as if it were not there.

=item IP Masquerade

This is when the firewall implemented in the kernel (via NAT, or networking
address translation), it allows you to hide a complete network behind one
IP address. With this firewall no special compiling is needed as you can
access hosts directly.

For accessing ftp servers behind such firewalls you usually need to
set the environment variable C<FTP_PASSIVE> or the config variable
ftp_passive to a true value.

=back

=back

=head2 Configuring lynx or ncftp for going through a firewall

If you can go through your firewall with e.g. lynx, presumably with a
command such as

    /usr/local/bin/lynx -pscott:tiger

then you would configure CPAN.pm with the command

    o conf lynx "/usr/local/bin/lynx -pscott:tiger"

That's all. Similarly for ncftp or ftp, you would configure something
like

    o conf ncftp "/usr/bin/ncftp -f /home/scott/ncftplogin.cfg"

Your mileage may vary...

=head1 FAQ

=over 4

=item 1)

I installed a new version of module X but CPAN keeps saying,
I have the old version installed

Probably you B<do> have the old version installed. This can
happen if a module installs itself into a different directory in the
@INC path than it was previously installed. This is not really a
CPAN.pm problem, you would have the same problem when installing the
module manually. The easiest way to prevent this behaviour is to add
the argument C<UNINST=1> to the C<make install> call, and that is why
many people add this argument permanently by configuring

  o conf make_install_arg UNINST=1

=item 2)

So why is UNINST=1 not the default?

Because there are people who have their precise expectations about who
may install where in the @INC path and who uses which @INC array. In
fine tuned environments C<UNINST=1> can cause damage.

=item 3)

I want to clean up my mess, and install a new perl along with
all modules I have. How do I go about it?

Run the autobundle command for your old perl and optionally rename the
resulting bundle file (e.g. Bundle/mybundle.pm), install the new perl
with the Configure option prefix, e.g.

    ./Configure -Dprefix=/usr/local/perl-5.6.78.9

Install the bundle file you produced in the first step with something like

    cpan> install Bundle::mybundle

and you're done.

=item 4)

When I install bundles or multiple modules with one command
there is too much output to keep track of.

You may want to configure something like

  o conf make_arg "| tee -ai /root/.cpan/logs/make.out"
  o conf make_install_arg "| tee -ai /root/.cpan/logs/make_install.out"

so that STDOUT is captured in a file for later inspection.


=item 5)

I am not root, how can I install a module in a personal directory?

As of CPAN 1.9463, if you do not have permission to write the default perl
library directories, CPAN's configuration process will ask you whether
you want to bootstrap <local::lib>, which makes keeping a personal
perl library directory easy.

Another thing you should bear in mind is that the UNINST parameter can
be dangerous when you are installing into a private area because you
might accidentally remove modules that other people depend on that are
not using the private area.

=item 6)

How to get a package, unwrap it, and make a change before building it?

Have a look at the C<look> (!) command.

=item 7)

I installed a Bundle and had a couple of fails. When I
retried, everything resolved nicely. Can this be fixed to work
on first try?

The reason for this is that CPAN does not know the dependencies of all
modules when it starts out. To decide about the additional items to
install, it just uses data found in the META.yml file or the generated
Makefile. An undetected missing piece breaks the process. But it may
well be that your Bundle installs some prerequisite later than some
depending item and thus your second try is able to resolve everything.
Please note, CPAN.pm does not know the dependency tree in advance and
cannot sort the queue of things to install in a topologically correct
order. It resolves perfectly well B<if> all modules declare the
prerequisites correctly with the PREREQ_PM attribute to MakeMaker or
the C<requires> stanza of Module::Build. For bundles which fail and
you need to install often, it is recommended to sort the Bundle
definition file manually.

=item 8)

In our intranet, we have many modules for internal use. How
can I integrate these modules with CPAN.pm but without uploading
the modules to CPAN?

Have a look at the CPAN::Site module.

=item 9)

When I run CPAN's shell, I get an error message about things in my
C</etc/inputrc> (or C<~/.inputrc>) file.

These are readline issues and can only be fixed by studying readline
configuration on your architecture and adjusting the referenced file
accordingly. Please make a backup of the C</etc/inputrc> or C<~/.inputrc>
and edit them. Quite often harmless changes like uppercasing or
lowercasing some arguments solves the problem.

=item 10)

Some authors have strange characters in their names.

Internally CPAN.pm uses the UTF-8 charset. If your terminal is
expecting ISO-8859-1 charset, a converter can be activated by setting
term_is_latin to a true value in your config file. One way of doing so
would be

    cpan> o conf term_is_latin 1

If other charset support is needed, please file a bug report against
CPAN.pm at rt.cpan.org and describe your needs. Maybe we can extend
the support or maybe UTF-8 terminals become widely available.

Note: this config variable is deprecated and will be removed in a
future version of CPAN.pm. It will be replaced with the conventions
around the family of $LANG and $LC_* environment variables.

=item 11)

When an install fails for some reason and then I correct the error
condition and retry, CPAN.pm refuses to install the module, saying
C<Already tried without success>.

Use the force pragma like so

  force install Foo::Bar

Or you can use

  look Foo::Bar

and then C<make install> directly in the subshell.

=item 12)

How do I install a "DEVELOPER RELEASE" of a module?

By default, CPAN will install the latest non-developer release of a
module. If you want to install a dev release, you have to specify the
partial path starting with the author id to the tarball you wish to
install, like so:

    cpan> install KWILLIAMS/Module-Build-0.27_07.tar.gz

Note that you can use the C<ls> command to get this path listed.

=item 13)

How do I install a module and all its dependencies from the commandline,
without being prompted for anything, despite my CPAN configuration
(or lack thereof)?

CPAN uses ExtUtils::MakeMaker's prompt() function to ask its questions, so
if you set the PERL_MM_USE_DEFAULT environment variable, you shouldn't be
asked any questions at all (assuming the modules you are installing are
nice about obeying that variable as well):

    % PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'install My::Module'

=item 14)

How do I create a Module::Build based Build.PL derived from an
ExtUtils::MakeMaker focused Makefile.PL?

http://search.cpan.org/dist/Module-Build-Convert/

=item 15)

I'm frequently irritated with the CPAN shell's inability to help me
select a good mirror.

CPAN can now help you select a "good" mirror, based on which ones have the
lowest 'ping' round-trip times.  From the shell, use the command 'o conf init
urllist' and allow CPAN to automatically select mirrors for you.

Beyond that help, the urllist config parameter is yours. You can add and remove
sites at will. You should find out which sites have the best up-to-dateness,
bandwidth, reliability, etc. and are topologically close to you. Some people
prefer fast downloads, others up-to-dateness, others reliability.  You decide
which to try in which order.

Henk P. Penning maintains a site that collects data about CPAN sites:

  http://mirrors.cpan.org/

Also, feel free to play with experimental features. Run

  o conf init randomize_urllist ftpstats_period ftpstats_size

and choose your favorite parameters. After a few downloads running the
C<hosts> command will probably assist you in choosing the best mirror
sites.

=item 16)

Why do I get asked the same questions every time I start the shell?

You can make your configuration changes permanent by calling the
command C<o conf commit>. Alternatively set the C<auto_commit>
variable to true by running C<o conf init auto_commit> and answering
the following question with yes.

=item 17)

Older versions of CPAN.pm had the original root directory of all
tarballs in the build directory. Now there are always random
characters appended to these directory names. Why was this done?

The random characters are provided by File::Temp and ensure that each
module's individual build directory is unique. This makes running
CPAN.pm in concurrent processes simultaneously safe.

=item 18)

Speaking of the build directory. Do I have to clean it up myself?

You have the choice to set the config variable C<scan_cache> to
C<never>. Then you must clean it up yourself. The other possible
values, C<atstart> and C<atexit> clean up the build directory when you
start (or more precisely, after the first extraction into the build
directory) or exit the CPAN shell, respectively. If you never start up
the CPAN shell, you probably also have to clean up the build directory
yourself.

=item 19)

How can I switch to sudo instead of local::lib?

The following 5 environment veriables need to be reset to the previous
values: PATH, PERL5LIB, PERL_LOCAL_LIB_ROOT, PERL_MB_OPT, PERL_MM_OPT;
and these two CPAN.pm config variables must be reconfigured:
make_install_make_command and mbuild_install_build_command. The five
env variables have probably been overwritten in your $HOME/.bashrc or
some equivalent. You either find them there and delete their traces
and logout/login or you override them temporarily, depending on your
exact desire. The two cpanpm config variables can be set with:

  o conf init /install_.*_command/

probably followed by

  o conf commit

=back

=head1 COMPATIBILITY

=head2 OLD PERL VERSIONS

CPAN.pm is regularly tested to run under 5.005 and assorted
newer versions. It is getting more and more difficult to get the
minimal prerequisites working on older perls. It is close to
impossible to get the whole Bundle::CPAN working there. If you're in
the position to have only these old versions, be advised that CPAN is
designed to work fine without the Bundle::CPAN installed.

To get things going, note that GBARR/Scalar-List-Utils-1.18.tar.gz is
compatible with ancient perls and that File::Temp is listed as a
prerequisite but CPAN has reasonable workarounds if it is missing.

=head2 CPANPLUS

This module and its competitor, the CPANPLUS module, are both much
cooler than the other. CPAN.pm is older. CPANPLUS was designed to be
more modular, but it was never intended to be compatible with CPAN.pm.

=head2 CPANMINUS

In the year 2010 App::cpanminus was launched as a new approach to a
cpan shell with a considerably smaller footprint. Very cool stuff.

=head1 SECURITY ADVICE

This software enables you to upgrade software on your computer and so
is inherently dangerous because the newly installed software may
contain bugs and may alter the way your computer works or even make it
unusable. Please consider backing up your data before every upgrade.

=head1 BUGS

Please report bugs via L<http://rt.cpan.org/>

Before submitting a bug, please make sure that the traditional method
of building a Perl module package from a shell by following the
installation instructions of that package still works in your
environment.

=head1 AUTHOR

Andreas Koenig C<< <andk@cpan.org> >>

=head1 LICENSE

This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>

=head1 TRANSLATIONS

Kawai,Takanori provides a Japanese translation of a very old version
of this manpage at
L<http://homepage3.nifty.com/hippo2000/perltips/CPAN.htm>

=head1 SEE ALSO

Many people enter the CPAN shell by running the L<cpan> utility
program which is installed in the same directory as perl itself. So if
you have this directory in your PATH variable (or some equivalent in
your operating system) then typing C<cpan> in a console window will
work for you as well. Above that the utility provides several
commandline shortcuts.

The main CPAN website, which includes general information about the
service, is at L<http://www.cpan.org/>.

melezhik (Alexey) sent me a link where he published a chef recipe to
work with CPAN.pm: http://community.opscode.com/cookbooks/cpan.


=cut
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             /// <reference types="node" />
import { ExceptionOptionType as __ExceptionOptionType } from "@aws-sdk/smithy-client";
import { Readable } from "stream";
import { ChecksumAlgorithm, Grant, ObjectCannedACL, ObjectLockLegalHoldStatus, ObjectLockMode, ObjectLockRetention, PublicAccessBlockConfiguration, ReplicationStatus, RequestCharged, RequestPayer, ServerSideEncryption, StorageClass, Tagging } from "./models_0";
import { S3ServiceException as __BaseException } from "./S3ServiceException";
/**
 * @public
 */
export interface PutObjectRetentionOutput {
    /**
     * <p>If present, indicates that the requester was successfully charged for the
     *          request.</p>
     */
    RequestCharged?: RequestCharged | string;
}
/**
 * @public
 */
export interface PutObjectRetentionRequest {
    /**
     * <p>The bucket name that contains the object you want to apply this Object Retention
     *          configuration to. </p>
     *          <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>The key name for the object that you want to apply this Object Retention configuration
     *          to.</p>
     */
    Key: string | undefined;
    /**
     * <p>The container element for the Object Retention configuration.</p>
     */
    Retention?: ObjectLockRetention;
    /**
     * <p>Confirms that the requester knows that they will be charged for the request. Bucket
     *          owners need not specify this parameter in their requests. For information about downloading
     *          objects from Requester Pays buckets, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html">Downloading Objects in
     *             Requester Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    RequestPayer?: RequestPayer | string;
    /**
     * <p>The version ID for the object that you want to apply this Object Retention configuration
     *          to.</p>
     */
    VersionId?: string;
    /**
     * <p>Indicates whether this action should bypass Governance-mode restrictions.</p>
     */
    BypassGovernanceRetention?: boolean;
    /**
     * <p>The MD5 hash for the request body.</p>
     *          <p>For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is calculated automatically.</p>
     */
    ContentMD5?: string;
    /**
     * <p>Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any
     *     additional functionality if not using the SDK. When sending this header, there must be a corresponding <code>x-amz-checksum</code> or
     *     <code>x-amz-trailer</code> header sent. Otherwise, Amazon S3 fails the request with the HTTP status code <code>400 Bad Request</code>. For more
     *     information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in
     *     the <i>Amazon S3 User Guide</i>.</p>
     *          <p>If you provide an individual checksum, Amazon S3 ignores any provided
     *             <code>ChecksumAlgorithm</code> parameter.</p>
     */
    ChecksumAlgorithm?: ChecksumAlgorithm | string;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
}
/**
 * @public
 */
export interface PutObjectTaggingOutput {
    /**
     * <p>The versionId of the object the tag-set was added to.</p>
     */
    VersionId?: string;
}
/**
 * @public
 */
export interface PutObjectTaggingRequest {
    /**
     * <p>The bucket name containing the object. </p>
     *          <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <code>
     *                <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com</code>. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html">What is S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>Name of the object key.</p>
     */
    Key: string | undefined;
    /**
     * <p>The versionId of the object that the tag-set will be added to.</p>
     */
    VersionId?: string;
    /**
     * <p>The MD5 hash for the request body.</p>
     *          <p>For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is calculated automatically.</p>
     */
    ContentMD5?: string;
    /**
     * <p>Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any
     *     additional functionality if not using the SDK. When sending this header, there must be a corresponding <code>x-amz-checksum</code> or
     *     <code>x-amz-trailer</code> header sent. Otherwise, Amazon S3 fails the request with the HTTP status code <code>400 Bad Request</code>. For more
     *     information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in
     *     the <i>Amazon S3 User Guide</i>.</p>
     *          <p>If you provide an individual checksum, Amazon S3 ignores any provided
     *             <code>ChecksumAlgorithm</code> parameter.</p>
     */
    ChecksumAlgorithm?: ChecksumAlgorithm | string;
    /**
     * <p>Container for the <code>TagSet</code> and <code>Tag</code> elements</p>
     */
    Tagging: Tagging | undefined;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
    /**
     * <p>Confirms that the requester knows that they will be charged for the request. Bucket
     *          owners need not specify this parameter in their requests. For information about downloading
     *          objects from Requester Pays buckets, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html">Downloading Objects in
     *             Requester Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    RequestPayer?: RequestPayer | string;
}
/**
 * @public
 */
export interface PutPublicAccessBlockRequest {
    /**
     * <p>The name of the Amazon S3 bucket whose <code>PublicAccessBlock</code> configuration you want
     *          to set.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>The MD5 hash of the <code>PutPublicAccessBlock</code> request body. </p>
     *          <p>For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is calculated automatically.</p>
     */
    ContentMD5?: string;
    /**
     * <p>Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any
     *     additional functionality if not using the SDK. When sending this header, there must be a corresponding <code>x-amz-checksum</code> or
     *     <code>x-amz-trailer</code> header sent. Otherwise, Amazon S3 fails the request with the HTTP status code <code>400 Bad Request</code>. For more
     *     information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in
     *     the <i>Amazon S3 User Guide</i>.</p>
     *          <p>If you provide an individual checksum, Amazon S3 ignores any provided
     *             <code>ChecksumAlgorithm</code> parameter.</p>
     */
    ChecksumAlgorithm?: ChecksumAlgorithm | string;
    /**
     * <p>The <code>PublicAccessBlock</code> configuration that you want to apply to this Amazon S3
     *          bucket. You can enable the configuration options in any combination. For more information
     *          about when Amazon S3 considers a bucket or object public, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status">The Meaning of "Public"</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | undefined;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
}
/**
 * @public
 * <p>This action is not allowed against this storage tier.</p>
 */
export declare class ObjectAlreadyInActiveTierError extends __BaseException {
    readonly name: "ObjectAlreadyInActiveTierError";
    readonly $fault: "client";
    /**
     * @internal
     */
    constructor(opts: __ExceptionOptionType<ObjectAlreadyInActiveTierError, __BaseException>);
}
/**
 * @public
 */
export interface RestoreObjectOutput {
    /**
     * <p>If present, indicates that the requester was successfully charged for the
     *          request.</p>
     */
    RequestCharged?: RequestCharged | string;
    /**
     * <p>Indicates the path in the provided S3 output location where Select results will be
     *          restored to.</p>
     */
    RestoreOutputPath?: string;
}
/**
 * @public
 * @enum
 */
export declare const Tier: {
    readonly Bulk: "Bulk";
    readonly Expedited: "Expedited";
    readonly Standard: "Standard";
};
/**
 * @public
 */
export type Tier = (typeof Tier)[keyof typeof Tier];
/**
 * @public
 * <p>Container for S3 Glacier job parameters.</p>
 */
export interface GlacierJobParameters {
    /**
     * <p>Retrieval tier at which the restore will be processed.</p>
     */
    Tier: Tier | string | undefined;
}
/**
 * @public
 * <p>Contains the type of server-side encryption used.</p>
 */
export interface Encryption {
    /**
     * <p>The server-side encryption algorithm used when storing job results in Amazon S3 (for example,
     *          AES256, <code>aws:kms</code>).</p>
     */
    EncryptionType: ServerSideEncryption | string | undefined;
    /**
     * <p>If the encryption type is <code>aws:kms</code>, this optional value specifies the ID of
     *          the symmetric encryption customer managed key to use for encryption of job results. Amazon S3 only
     *          supports symmetric encryption KMS keys. For more information, see <a href="https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html">Asymmetric keys in Amazon Web Services KMS</a> in the <i>Amazon Web Services Key Management Service
     *             Developer Guide</i>.</p>
     */
    KMSKeyId?: string;
    /**
     * <p>If the encryption type is <code>aws:kms</code>, this optional value can be used to
     *          specify the encryption context for the restore results.</p>
     */
    KMSContext?: string;
}
/**
 * @public
 * <p>A metadata key-value pair to store with an object.</p>
 */
export interface MetadataEntry {
    /**
     * <p>Name of the Object.</p>
     */
    Name?: string;
    /**
     * <p>Value of the Object.</p>
     */
    Value?: string;
}
/**
 * @public
 * <p>Describes an Amazon S3 location that will receive the results of the restore request.</p>
 */
export interface S3Location {
    /**
     * <p>The name of the bucket where the restore results will be placed.</p>
     */
    BucketName: string | undefined;
    /**
     * <p>The prefix that is prepended to the restore results for this request.</p>
     */
    Prefix: string | undefined;
    /**
     * <p>Contains the type of server-side encryption used.</p>
     */
    Encryption?: Encryption;
    /**
     * <p>The canned ACL to apply to the restore results.</p>
     */
    CannedACL?: ObjectCannedACL | string;
    /**
     * <p>A list of grants that control access to the staged results.</p>
     */
    AccessControlList?: Grant[];
    /**
     * <p>The tag-set that is applied to the restore results.</p>
     */
    Tagging?: Tagging;
    /**
     * <p>A list of metadata to store with the restore results in S3.</p>
     */
    UserMetadata?: MetadataEntry[];
    /**
     * <p>The class of storage used to store the restore results.</p>
     */
    StorageClass?: StorageClass | string;
}
/**
 * @public
 * <p>Describes the location where the restore job's output is stored.</p>
 */
export interface OutputLocation {
    /**
     * <p>Describes an S3 location that will receive the results of the restore request.</p>
     */
    S3?: S3Location;
}
/**
 * @public
 * @enum
 */
export declare const ExpressionType: {
    readonly SQL: "SQL";
};
/**
 * @public
 */
export type ExpressionType = (typeof ExpressionType)[keyof typeof ExpressionType];
/**
 * @public
 * @enum
 */
export declare const CompressionType: {
    readonly BZIP2: "BZIP2";
    readonly GZIP: "GZIP";
    readonly NONE: "NONE";
};
/**
 * @public
 */
export type CompressionType = (typeof CompressionType)[keyof typeof CompressionType];
/**
 * @public
 * @enum
 */
export declare const FileHeaderInfo: {
    readonly IGNORE: "IGNORE";
    readonly NONE: "NONE";
    readonly USE: "USE";
};
/**
 * @public
 */
export type FileHeaderInfo = (typeof FileHeaderInfo)[keyof typeof FileHeaderInfo];
/**
 * @public
 * <p>Describes how an uncompressed comma-separated values (CSV)-formatted input object is
 *          formatted.</p>
 */
export interface CSVInput {
    /**
     * <p>Describes the first line of input. Valid values are:</p>
     *          <ul>
     *             <li>
     *                <p>
     *                   <code>NONE</code>: First line is not a header.</p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>IGNORE</code>: First line is a header, but you can't use the header values
     *                to indicate the column in an expression. You can use column position (such as _1, _2,
     *                …) to indicate the column (<code>SELECT s._1 FROM OBJECT s</code>).</p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>Use</code>: First line is a header, and you can use the header value to
     *                identify a column in an expression (<code>SELECT "name" FROM OBJECT</code>). </p>
     *             </li>
     *          </ul>
     */
    FileHeaderInfo?: FileHeaderInfo | string;
    /**
     * <p>A single character used to indicate that a row should be ignored when the character is
     *          present at the start of that row. You can specify any character to indicate a comment line.
     *          The default character is <code>#</code>.</p>
     *          <p>Default: <code>#</code>
     *          </p>
     */
    Comments?: string;
    /**
     * <p>A single character used for escaping the quotation mark character inside an already
     *          escaped value. For example, the value <code>""" a , b """</code> is parsed as <code>" a , b
     *             "</code>.</p>
     */
    QuoteEscapeCharacter?: string;
    /**
     * <p>A single character used to separate individual records in the input. Instead of the
     *          default value, you can specify an arbitrary delimiter.</p>
     */
    RecordDelimiter?: string;
    /**
     * <p>A single character used to separate individual fields in a record. You can specify an
     *          arbitrary delimiter.</p>
     */
    FieldDelimiter?: string;
    /**
     * <p>A single character used for escaping when the field delimiter is part of the value. For
     *          example, if the value is <code>a, b</code>, Amazon S3 wraps this field value in quotation marks,
     *          as follows: <code>" a , b "</code>.</p>
     *          <p>Type: String</p>
     *          <p>Default: <code>"</code>
     *          </p>
     *          <p>Ancestors: <code>CSV</code>
     *          </p>
     */
    QuoteCharacter?: string;
    /**
     * <p>Specifies that CSV field values may contain quoted record delimiters and such records
     *          should be allowed. Default value is FALSE. Setting this value to TRUE may lower
     *          performance.</p>
     */
    AllowQuotedRecordDelimiter?: boolean;
}
/**
 * @public
 * @enum
 */
export declare const JSONType: {
    readonly DOCUMENT: "DOCUMENT";
    readonly LINES: "LINES";
};
/**
 * @public
 */
export type JSONType = (typeof JSONType)[keyof typeof JSONType];
/**
 * @public
 * <p>Specifies JSON as object's input serialization format.</p>
 */
export interface JSONInput {
    /**
     * <p>The type of JSON. Valid values: Document, Lines.</p>
     */
    Type?: JSONType | string;
}
/**
 * @public
 * <p>Container for Parquet.</p>
 */
export interface ParquetInput {
}
/**
 * @public
 * <p>Describes the serialization format of the object.</p>
 */
export interface InputSerialization {
    /**
     * <p>Describes the serialization of a CSV-encoded object.</p>
     */
    CSV?: CSVInput;
    /**
     * <p>Specifies object's compression format. Valid values: NONE, GZIP, BZIP2. Default Value:
     *          NONE.</p>
     */
    CompressionType?: CompressionType | string;
    /**
     * <p>Specifies JSON as object's input serialization format.</p>
     */
    JSON?: JSONInput;
    /**
     * <p>Specifies Parquet as object's input serialization format.</p>
     */
    Parquet?: ParquetInput;
}
/**
 * @public
 * @enum
 */
export declare const QuoteFields: {
    readonly ALWAYS: "ALWAYS";
    readonly ASNEEDED: "ASNEEDED";
};
/**
 * @public
 */
export type QuoteFields = (typeof QuoteFields)[keyof typeof QuoteFields];
/**
 * @public
 * <p>Describes how uncompressed comma-separated values (CSV)-formatted results are
 *          formatted.</p>
 */
export interface CSVOutput {
    /**
     * <p>Indicates whether to use quotation marks around output fields. </p>
     *          <ul>
     *             <li>
     *                <p>
     *                   <code>ALWAYS</code>: Always use quotation marks for output fields.</p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>ASNEEDED</code>: Use quotation marks for output fields when needed.</p>
     *             </li>
     *          </ul>
     */
    QuoteFields?: QuoteFields | string;
    /**
     * <p>The single character used for escaping the quote character inside an already escaped
     *          value.</p>
     */
    QuoteEscapeCharacter?: string;
    /**
     * <p>A single character used to separate individual records in the output. Instead of the
     *          default value, you can specify an arbitrary delimiter.</p>
     */
    RecordDelimiter?: string;
    /**
     * <p>The value used to separate individual fields in a record. You can specify an arbitrary
     *          delimiter.</p>
     */
    FieldDelimiter?: string;
    /**
     * <p>A single character used for escaping when the field delimiter is part of the value. For
     *          example, if the value is <code>a, b</code>, Amazon S3 wraps this field value in quotation marks,
     *          as follows: <code>" a , b "</code>.</p>
     */
    QuoteCharacter?: string;
}
/**
 * @public
 * <p>Specifies JSON as request's output serialization format.</p>
 */
export interface JSONOutput {
    /**
     * <p>The value used to separate individual records in the output. If no value is specified,
     *          Amazon S3 uses a newline character ('\n').</p>
     */
    RecordDelimiter?: string;
}
/**
 * @public
 * <p>Describes how results of the Select job are serialized.</p>
 */
export interface OutputSerialization {
    /**
     * <p>Describes the serialization of CSV-encoded Select results.</p>
     */
    CSV?: CSVOutput;
    /**
     * <p>Specifies JSON as request's output serialization format.</p>
     */
    JSON?: JSONOutput;
}
/**
 * @public
 * <p>Describes the parameters for Select job types.</p>
 */
export interface SelectParameters {
    /**
     * <p>Describes the serialization format of the object.</p>
     */
    InputSerialization: InputSerialization | undefined;
    /**
     * <p>The type of the provided expression (for example, SQL).</p>
     */
    ExpressionType: ExpressionType | string | undefined;
    /**
     * <p>The expression that is used to query the object.</p>
     */
    Expression: string | undefined;
    /**
     * <p>Describes how the results of the Select job are serialized.</p>
     */
    OutputSerialization: OutputSerialization | undefined;
}
/**
 * @public
 * @enum
 */
export declare const RestoreRequestType: {
    readonly SELECT: "SELECT";
};
/**
 * @public
 */
export type RestoreRequestType = (typeof RestoreRequestType)[keyof typeof RestoreRequestType];
/**
 * @public
 * <p>Container for restore job parameters.</p>
 */
export interface RestoreRequest {
    /**
     * <p>Lifetime of the active copy in days. Do not use with restores that specify
     *             <code>OutputLocation</code>.</p>
     *          <p>The Days element is required for regular restores, and must not be provided for select
     *          requests.</p>
     */
    Days?: number;
    /**
     * <p>S3 Glacier related parameters pertaining to this job. Do not use with restores that
     *          specify <code>OutputLocation</code>.</p>
     */
    GlacierJobParameters?: GlacierJobParameters;
    /**
     * <p>Type of restore request.</p>
     */
    Type?: RestoreRequestType | string;
    /**
     * <p>Retrieval tier at which the restore will be processed.</p>
     */
    Tier?: Tier | string;
    /**
     * <p>The optional description for the job.</p>
     */
    Description?: string;
    /**
     * <p>Describes the parameters for Select job types.</p>
     */
    SelectParameters?: SelectParameters;
    /**
     * <p>Describes the location where the restore job's output is stored.</p>
     */
    OutputLocation?: OutputLocation;
}
/**
 * @public
 */
export interface RestoreObjectRequest {
    /**
     * <p>The bucket name containing the object to restore. </p>
     *          <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <code>
     *                <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com</code>. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html">What is S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>Object key for which the action was initiated.</p>
     */
    Key: string | undefined;
    /**
     * <p>VersionId used to reference a specific version of the object.</p>
     */
    VersionId?: string;
    /**
     * <p>Container for restore job parameters.</p>
     */
    RestoreRequest?: RestoreRequest;
    /**
     * <p>Confirms that the requester knows that they will be charged for the request. Bucket
     *          owners need not specify this parameter in their requests. For information about downloading
     *          objects from Requester Pays buckets, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html">Downloading Objects in
     *             Requester Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    RequestPayer?: RequestPayer | string;
    /**
     * <p>Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any
     *     additional functionality if not using the SDK. When sending this header, there must be a corresponding <code>x-amz-checksum</code> or
     *     <code>x-amz-trailer</code> header sent. Otherwise, Amazon S3 fails the request with the HTTP status code <code>400 Bad Request</code>. For more
     *     information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in
     *     the <i>Amazon S3 User Guide</i>.</p>
     *          <p>If you provide an individual checksum, Amazon S3 ignores any provided
     *             <code>ChecksumAlgorithm</code> parameter.</p>
     */
    ChecksumAlgorithm?: ChecksumAlgorithm | string;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
}
/**
 * @public
 * <p></p>
 */
export interface ContinuationEvent {
}
/**
 * @public
 * <p>A message that indicates the request is complete and no more messages will be sent. You
 *          should not assume that the request is complete until the client receives an
 *             <code>EndEvent</code>.</p>
 */
export interface EndEvent {
}
/**
 * @public
 * <p>This data type contains information about progress of an operation.</p>
 */
export interface Progress {
    /**
     * <p>The current number of object bytes scanned.</p>
     */
    BytesScanned?: number;
    /**
     * <p>The current number of uncompressed object bytes processed.</p>
     */
    BytesProcessed?: number;
    /**
     * <p>The current number of bytes of records payload data returned.</p>
     */
    BytesReturned?: number;
}
/**
 * @public
 * <p>This data type contains information about the progress event of an operation.</p>
 */
export interface ProgressEvent {
    /**
     * <p>The Progress event details.</p>
     */
    Details?: Progress;
}
/**
 * @public
 * <p>The container for the records event.</p>
 */
export interface RecordsEvent {
    /**
     * <p>The byte array of partial, one or more result records.</p>
     */
    Payload?: Uint8Array;
}
/**
 * @public
 * <p>Container for the stats details.</p>
 */
export interface Stats {
    /**
     * <p>The total number of object bytes scanned.</p>
     */
    BytesScanned?: number;
    /**
     * <p>The total number of uncompressed object bytes processed.</p>
     */
    BytesProcessed?: number;
    /**
     * <p>The total number of bytes of records payload data returned.</p>
     */
    BytesReturned?: number;
}
/**
 * @public
 * <p>Container for the Stats Event.</p>
 */
export interface StatsEvent {
    /**
     * <p>The Stats event details.</p>
     */
    Details?: Stats;
}
/**
 * @public
 * <p>The container for selecting objects from a content event stream.</p>
 */
export type SelectObjectContentEventStream = SelectObjectContentEventStream.ContMember | SelectObjectContentEventStream.EndMember | SelectObjectContentEventStream.ProgressMember | SelectObjectContentEventStream.RecordsMember | SelectObjectContentEventStream.StatsMember | SelectObjectContentEventStream.$UnknownMember;
/**
 * @public
 */
export declare namespace SelectObjectContentEventStream {
    /**
     * <p>The Records Event.</p>
     */
    interface RecordsMember {
        Records: RecordsEvent;
        Stats?: never;
        Progress?: never;
        Cont?: never;
        End?: never;
        $unknown?: never;
    }
    /**
     * <p>The Stats Event.</p>
     */
    interface StatsMember {
        Records?: never;
        Stats: StatsEvent;
        Progress?: never;
        Cont?: never;
        End?: never;
        $unknown?: never;
    }
    /**
     * <p>The Progress Event.</p>
     */
    interface ProgressMember {
        Records?: never;
        Stats?: never;
        Progress: ProgressEvent;
        Cont?: never;
        End?: never;
        $unknown?: never;
    }
    /**
     * <p>The Continuation Event.</p>
     */
    interface ContMember {
        Records?: never;
        Stats?: never;
        Progress?: never;
        Cont: ContinuationEvent;
        End?: never;
        $unknown?: never;
    }
    /**
     * <p>The End Event.</p>
     */
    interface EndMember {
        Records?: never;
        Stats?: never;
        Progress?: never;
        Cont?: never;
        End: EndEvent;
        $unknown?: never;
    }
    interface $UnknownMember {
        Records?: never;
        Stats?: never;
        Progress?: never;
        Cont?: never;
        End?: never;
        $unknown: [string, any];
    }
    interface Visitor<T> {
        Records: (value: RecordsEvent) => T;
        Stats: (value: StatsEvent) => T;
        Progress: (value: ProgressEvent) => T;
        Cont: (value: ContinuationEvent) => T;
        End: (value: EndEvent) => T;
        _: (name: string, value: any) => T;
    }
    const visit: <T>(value: SelectObjectContentEventStream, visitor: Visitor<T>) => T;
}
/**
 * @public
 */
export interface SelectObjectContentOutput {
    /**
     * <p>The array of results.</p>
     */
    Payload?: AsyncIterable<SelectObjectContentEventStream>;
}
/**
 * @public
 * <p>Container for specifying if periodic <code>QueryProgress</code> messages should be
 *          sent.</p>
 */
export interface RequestProgress {
    /**
     * <p>Specifies whether periodic QueryProgress frames should be sent. Valid values: TRUE,
     *          FALSE. Default value: FALSE.</p>
     */
    Enabled?: boolean;
}
/**
 * @public
 * <p>Specifies the byte range of the object to get the records from. A record is processed
 *          when its first byte is contained by the range. This parameter is optional, but when
 *          specified, it must not be empty. See RFC 2616, Section 14.35.1 about how to specify the
 *          start and end of the range.</p>
 */
export interface ScanRange {
    /**
     * <p>Specifies the start of the byte range. This parameter is optional. Valid values:
     *          non-negative integers. The default value is 0. If only <code>start</code> is supplied, it
     *          means scan from that point to the end of the file. For example,
     *             <code><scanrange><start>50</start></scanrange></code> means scan
     *          from byte 50 until the end of the file.</p>
     */
    Start?: number;
    /**
     * <p>Specifies the end of the byte range. This parameter is optional. Valid values:
     *          non-negative integers. The default value is one less than the size of the object being
     *          queried. If only the End parameter is supplied, it is interpreted to mean scan the last N
     *          bytes of the file. For example,
     *             <code><scanrange><end>50</end></scanrange></code> means scan the
     *          last 50 bytes.</p>
     */
    End?: number;
}
/**
 * @public
 * <p>Request to filter the contents of an Amazon S3 object based on a simple Structured Query
 *          Language (SQL) statement. In the request, along with the SQL expression, you must specify a
 *          data serialization format (JSON or CSV) of the object. Amazon S3 uses this to parse object data
 *          into records. It returns only records that match the specified SQL expression. You must
 *          also specify the data serialization format for the response. For more information, see
 *             <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectSELECTContent.html">S3Select API Documentation</a>.</p>
 */
export interface SelectObjectContentRequest {
    /**
     * <p>The S3 bucket.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>The object key.</p>
     */
    Key: string | undefined;
    /**
     * <p>The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created
     *     using a checksum algorithm. For more information,
     *     see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html">Protecting data using SSE-C keys</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p>The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm.
     *     For more information, see
     *     <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html">Protecting data using SSE-C keys</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    SSECustomerKey?: string;
    /**
     * <p>The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum
     *     algorithm. For more information,
     *     see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html">Protecting data using SSE-C keys</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>The expression that is used to query the object.</p>
     */
    Expression: string | undefined;
    /**
     * <p>The type of the provided expression (for example, SQL).</p>
     */
    ExpressionType: ExpressionType | string | undefined;
    /**
     * <p>Specifies if periodic request progress information should be enabled.</p>
     */
    RequestProgress?: RequestProgress;
    /**
     * <p>Describes the format of the data in the object that is being queried.</p>
     */
    InputSerialization: InputSerialization | undefined;
    /**
     * <p>Describes the format of the data that you want Amazon S3 to return in response.</p>
     */
    OutputSerialization: OutputSerialization | undefined;
    /**
     * <p>Specifies the byte range of the object to get the records from. A record is processed
     *          when its first byte is contained by the range. This parameter is optional, but when
     *          specified, it must not be empty. See RFC 2616, Section 14.35.1 about how to specify the
     *          start and end of the range.</p>
     *          <p>
     *             <code>ScanRange</code>may be used in the following ways:</p>
     *          <ul>
     *             <li>
     *                <p>
     *                   <code><scanrange><start>50</start><end>100</end></scanrange></code>
     *                - process only the records starting between the bytes 50 and 100 (inclusive, counting
     *                from zero)</p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code><scanrange><start>50</start></scanrange></code> -
     *                process only the records starting after the byte 50</p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code><scanrange><end>50</end></scanrange></code> -
     *                process only the records within the last 50 bytes of the file.</p>
     *             </li>
     *          </ul>
     */
    ScanRange?: ScanRange;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
}
/**
 * @public
 */
export interface UploadPartOutput {
    /**
     * <p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example,
     *          AES256, <code>aws:kms</code>).</p>
     */
    ServerSideEncryption?: ServerSideEncryption | string;
    /**
     * <p>Entity tag for the uploaded object.</p>
     */
    ETag?: string;
    /**
     * <p>The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32?: string;
    /**
     * <p>The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32C?: string;
    /**
     * <p>The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA1?: string;
    /**
     * <p>The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA256?: string;
    /**
     * <p>If server-side encryption with a customer-provided encryption key was requested, the
     *          response will include this header confirming the encryption algorithm used.</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p>If server-side encryption with a customer-provided encryption key was requested, the
     *          response will include this header to provide round-trip message integrity verification of
     *          the customer-provided encryption key.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>If present, specifies the ID of the Amazon Web Services Key Management Service (Amazon Web Services KMS) symmetric
     *          encryption customer managed key was used for the object.</p>
     */
    SSEKMSKeyId?: string;
    /**
     * <p>Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption
     *          with Amazon Web Services KMS (SSE-KMS).</p>
     */
    BucketKeyEnabled?: boolean;
    /**
     * <p>If present, indicates that the requester was successfully charged for the
     *          request.</p>
     */
    RequestCharged?: RequestCharged | string;
}
/**
 * @public
 */
export interface UploadPartRequest {
    /**
     * <p>Object data.</p>
     */
    Body?: Readable | ReadableStream | Blob;
    /**
     * <p>The name of the bucket to which the multipart upload was initiated.</p>
     *          <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <code>
     *                <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com</code>. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html">What is S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>Size of the body in bytes. This parameter is useful when the size of the body cannot be
     *          determined automatically.</p>
     */
    ContentLength?: number;
    /**
     * <p>The base64-encoded 128-bit MD5 digest of the part data. This parameter is auto-populated
     *          when using the command from the CLI. This parameter is required if object lock parameters
     *          are specified.</p>
     */
    ContentMD5?: string;
    /**
     * <p>Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any
     *     additional functionality if not using the SDK. When sending this header, there must be a corresponding <code>x-amz-checksum</code> or
     *     <code>x-amz-trailer</code> header sent. Otherwise, Amazon S3 fails the request with the HTTP status code <code>400 Bad Request</code>. For more
     *     information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in
     *     the <i>Amazon S3 User Guide</i>.</p>
     *          <p>If you provide an individual checksum, Amazon S3 ignores any provided
     *             <code>ChecksumAlgorithm</code> parameter.</p>
     *          <p>This checksum algorithm must be the same for all parts and it match the checksum value
     *          supplied in the <code>CreateMultipartUpload</code> request.</p>
     */
    ChecksumAlgorithm?: ChecksumAlgorithm | string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.
     *     This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see
     *     <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.
     *     This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more information, see
     *     <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32C?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.
     *     This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information, see
     *     <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA1?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.
     *     This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more information, see
     *     <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object integrity</a> in the
     *     <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA256?: string;
    /**
     * <p>Object key for which the multipart upload was initiated.</p>
     */
    Key: string | undefined;
    /**
     * <p>Part number of part being uploaded. This is a positive integer between 1 and
     *          10,000.</p>
     */
    PartNumber: number | undefined;
    /**
     * <p>Upload ID identifying the multipart upload whose part is being uploaded.</p>
     */
    UploadId: string | undefined;
    /**
     * <p>Specifies the algorithm to use to when encrypting the object (for example,
     *          AES256).</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This
     *          value is used to store the object and then it is discarded; Amazon S3 does not store the
     *          encryption key. The key must be appropriate for use with the algorithm specified in the
     *             <code>x-amz-server-side-encryption-customer-algorithm header</code>. This must be the
     *          same encryption key specified in the initiate multipart upload request.</p>
     */
    SSECustomerKey?: string;
    /**
     * <p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses
     *          this header for a message integrity check to ensure that the encryption key was transmitted
     *          without error.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>Confirms that the requester knows that they will be charged for the request. Bucket
     *          owners need not specify this parameter in their requests. For information about downloading
     *          objects from Requester Pays buckets, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html">Downloading Objects in
     *             Requester Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    RequestPayer?: RequestPayer | string;
    /**
     * <p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
}
/**
 * @public
 * <p>Container for all response elements.</p>
 */
export interface CopyPartResult {
    /**
     * <p>Entity tag of the object.</p>
     */
    ETag?: string;
    /**
     * <p>Date and time at which the object was uploaded.</p>
     */
    LastModified?: Date;
    /**
     * <p>The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32?: string;
    /**
     * <p>The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumCRC32C?: string;
    /**
     * <p>The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA1?: string;
    /**
     * <p>The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded
     *     with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated
     *     with multipart uploads, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums">
     *     Checking object integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    ChecksumSHA256?: string;
}
/**
 * @public
 */
export interface UploadPartCopyOutput {
    /**
     * <p>The version of the source object that was copied, if you have enabled versioning on the
     *          source bucket.</p>
     */
    CopySourceVersionId?: string;
    /**
     * <p>Container for all response elements.</p>
     */
    CopyPartResult?: CopyPartResult;
    /**
     * <p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example,
     *          AES256, <code>aws:kms</code>).</p>
     */
    ServerSideEncryption?: ServerSideEncryption | string;
    /**
     * <p>If server-side encryption with a customer-provided encryption key was requested, the
     *          response will include this header confirming the encryption algorithm used.</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p>If server-side encryption with a customer-provided encryption key was requested, the
     *          response will include this header to provide round-trip message integrity verification of
     *          the customer-provided encryption key.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>If present, specifies the ID of the Amazon Web Services Key Management Service (Amazon Web Services KMS) symmetric
     *          encryption customer managed key that was used for the object.</p>
     */
    SSEKMSKeyId?: string;
    /**
     * <p>Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption
     *          with Amazon Web Services KMS (SSE-KMS).</p>
     */
    BucketKeyEnabled?: boolean;
    /**
     * <p>If present, indicates that the requester was successfully charged for the
     *          request.</p>
     */
    RequestCharged?: RequestCharged | string;
}
/**
 * @public
 */
export interface UploadPartCopyRequest {
    /**
     * <p>The bucket name.</p>
     *          <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <code>
     *                <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com</code>. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html">What is S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>
     * <p>Note: To supply the Multi-region Access Point (MRAP) to Bucket, you need to install the "@aws-sdk/signature-v4-crt" package to your project dependencies.
     * For more information, please go to https://github.com/aws/aws-sdk-js-v3#known-issues</p>
     */
    Bucket: string | undefined;
    /**
     * <p>Specifies the source object for the copy operation. You specify the value in one of two
     *          formats, depending on whether you want to access the source object through an <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html">access point</a>:</p>
     *          <ul>
     *             <li>
     *                <p>For objects not accessed through an access point, specify the name of the source bucket
     *                and key of the source object, separated by a slash (/). For example, to copy the
     *                object <code>reports/january.pdf</code> from the bucket
     *                <code>awsexamplebucket</code>, use <code>awsexamplebucket/reports/january.pdf</code>.
     *                The value must be URL-encoded.</p>
     *             </li>
     *             <li>
     *                <p>For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format <code>arn:aws:s3:<Region>:<account-id>:accesspoint/<access-point-name>/object/<key></code>. For example, to copy the object <code>reports/january.pdf</code> through access point <code>my-access-point</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf</code>. The value must be URL encoded.</p>
     *                <note>
     *                   <p>Amazon S3 supports copy operations using access points only when the source and destination buckets are in the same Amazon Web Services Region.</p>
     *                </note>
     *                <p>Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format <code>arn:aws:s3-outposts:<Region>:<account-id>:outpost/<outpost-id>/object/<key></code>. For example, to copy the object <code>reports/january.pdf</code> through outpost <code>my-outpost</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf</code>. The value must be URL-encoded.  </p>
     *             </li>
     *          </ul>
     *          <p>To copy a specific version of an object, append <code>?versionId=<version-id></code>
     *          to the value (for example,
     *             <code>awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893</code>).
     *          If you don't specify a version ID, Amazon S3 copies the latest version of the source
     *          object.</p>
     */
    CopySource: string | undefined;
    /**
     * <p>Copies the object if its entity tag (ETag) matches the specified tag.</p>
     */
    CopySourceIfMatch?: string;
    /**
     * <p>Copies the object if it has been modified since the specified time.</p>
     */
    CopySourceIfModifiedSince?: Date;
    /**
     * <p>Copies the object if its entity tag (ETag) is different than the specified ETag.</p>
     */
    CopySourceIfNoneMatch?: string;
    /**
     * <p>Copies the object if it hasn't been modified since the specified time.</p>
     */
    CopySourceIfUnmodifiedSince?: Date;
    /**
     * <p>The range of bytes to copy from the source object. The range value must use the form
     *          bytes=first-last, where the first and last are the zero-based byte offsets to copy. For
     *          example, bytes=0-9 indicates that you want to copy the first 10 bytes of the source. You
     *          can copy a range only if the source object is greater than 5 MB.</p>
     */
    CopySourceRange?: string;
    /**
     * <p>Object key for which the multipart upload was initiated.</p>
     */
    Key: string | undefined;
    /**
     * <p>Part number of part being copied. This is a positive integer between 1 and
     *          10,000.</p>
     */
    PartNumber: number | undefined;
    /**
     * <p>Upload ID identifying the multipart upload whose part is being copied.</p>
     */
    UploadId: string | undefined;
    /**
     * <p>Specifies the algorithm to use to when encrypting the object (for example,
     *          AES256).</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This
     *          value is used to store the object and then it is discarded; Amazon S3 does not store the
     *          encryption key. The key must be appropriate for use with the algorithm specified in the
     *             <code>x-amz-server-side-encryption-customer-algorithm</code> header. This must be the
     *          same encryption key specified in the initiate multipart upload request.</p>
     */
    SSECustomerKey?: string;
    /**
     * <p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses
     *          this header for a message integrity check to ensure that the encryption key was transmitted
     *          without error.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>Specifies the algorithm to use when decrypting the source object (for example,
     *          AES256).</p>
     */
    CopySourceSSECustomerAlgorithm?: string;
    /**
     * <p>Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source
     *          object. The encryption key provided in this header must be one that was used when the
     *          source object was created.</p>
     */
    CopySourceSSECustomerKey?: string;
    /**
     * <p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses
     *          this header for a message integrity check to ensure that the encryption key was transmitted
     *          without error.</p>
     */
    CopySourceSSECustomerKeyMD5?: string;
    /**
     * <p>Confirms that the requester knows that they will be charged for the request. Bucket
     *          owners need not specify this parameter in their requests. For information about downloading
     *          objects from Requester Pays buckets, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html">Downloading Objects in
     *             Requester Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>
     */
    RequestPayer?: RequestPayer | string;
    /**
     * <p>The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedBucketOwner?: string;
    /**
     * <p>The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request fails with the HTTP status code <code>403 Forbidden</code> (access denied).</p>
     */
    ExpectedSourceBucketOwner?: string;
}
/**
 * @public
 */
export interface WriteGetObjectResponseRequest {
    /**
     * <p>Route prefix to the HTTP URL generated.</p>
     */
    RequestRoute: string | undefined;
    /**
     * <p>A single use encrypted token that maps <code>WriteGetObjectResponse</code> to the end
     *          user <code>GetObject</code> request.</p>
     */
    RequestToken: string | undefined;
    /**
     * <p>The object data.</p>
     */
    Body?: Readable | ReadableStream | Blob;
    /**
     * <p>The integer status code for an HTTP response of a corresponding <code>GetObject</code>
     *          request. The following is a list of status codes.</p>
     *          <ul>
     *             <li>
     *                <p>
     *                   <code>200 - OK</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>206 - Partial Content</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>304 - Not Modified</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>400 - Bad Request</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>401 - Unauthorized</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>403 - Forbidden</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>404 - Not Found</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>405 - Method Not Allowed</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>409 - Conflict</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>411 - Length Required</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>412 - Precondition Failed</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>416 - Range Not Satisfiable</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>500 - Internal Server Error</code>
     *                </p>
     *             </li>
     *             <li>
     *                <p>
     *                   <code>503 - Service Unavailable</code>
     *                </p>
     *             </li>
     *          </ul>
     */
    StatusCode?: number;
    /**
     * <p>A string that uniquely identifies an error condition. Returned in the <Code> tag
     *          of the error XML response for a corresponding <code>GetObject</code> call. Cannot be used
     *          with a successful <code>StatusCode</code> header or when the transformed object is provided
     *          in the body. All error codes from S3 are sentence-cased. The regular expression (regex)
     *          value is <code>"^[A-Z][a-zA-Z]+$"</code>.</p>
     */
    ErrorCode?: string;
    /**
     * <p>Contains a generic description of the error condition. Returned in the <Message>
     *          tag of the error XML response for a corresponding <code>GetObject</code> call. Cannot be
     *          used with a successful <code>StatusCode</code> header or when the transformed object is
     *          provided in body.</p>
     */
    ErrorMessage?: string;
    /**
     * <p>Indicates that a range of bytes was specified.</p>
     */
    AcceptRanges?: string;
    /**
     * <p>Specifies caching behavior along the request/reply chain.</p>
     */
    CacheControl?: string;
    /**
     * <p>Specifies presentational information for the object.</p>
     */
    ContentDisposition?: string;
    /**
     * <p>Specifies what content encodings have been applied to the object and thus what decoding
     *          mechanisms must be applied to obtain the media-type referenced by the Content-Type header
     *          field.</p>
     */
    ContentEncoding?: string;
    /**
     * <p>The language the content is in.</p>
     */
    ContentLanguage?: string;
    /**
     * <p>The size of the content body in bytes.</p>
     */
    ContentLength?: number;
    /**
     * <p>The portion of the object returned in the response.</p>
     */
    ContentRange?: string;
    /**
     * <p>A standard MIME type describing the format of the object data.</p>
     */
    ContentType?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is
     *          the same data that was originally sent. This specifies the base64-encoded, 32-bit CRC32
     *          checksum of the object returned by the Object Lambda function. This may not match the
     *          checksum for the object stored in Amazon S3. Amazon S3 will perform validation of the checksum values
     *          only when the original <code>GetObject</code> request required checksum validation. For
     *          more information about checksums, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object
     *             integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>Only one checksum header can be specified at a time. If you supply multiple checksum
     *          headers, this request will fail.</p>
     *          <p></p>
     */
    ChecksumCRC32?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is
     *          the same data that was originally sent. This specifies the base64-encoded, 32-bit CRC32C
     *          checksum of the object returned by the Object Lambda function. This may not match the
     *          checksum for the object stored in Amazon S3. Amazon S3 will perform validation of the checksum values
     *          only when the original <code>GetObject</code> request required checksum validation. For
     *          more information about checksums, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object
     *             integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>Only one checksum header can be specified at a time. If you supply multiple checksum
     *          headers, this request will fail.</p>
     */
    ChecksumCRC32C?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is
     *          the same data that was originally sent. This specifies the base64-encoded, 160-bit SHA-1
     *          digest of the object returned by the Object Lambda function. This may not match the
     *          checksum for the object stored in Amazon S3. Amazon S3 will perform validation of the checksum values
     *          only when the original <code>GetObject</code> request required checksum validation. For
     *          more information about checksums, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object
     *             integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>Only one checksum header can be specified at a time. If you supply multiple checksum
     *          headers, this request will fail.</p>
     */
    ChecksumSHA1?: string;
    /**
     * <p>This header can be used as a data integrity check to verify that the data received is
     *          the same data that was originally sent. This specifies the base64-encoded, 256-bit SHA-256
     *          digest of the object returned by the Object Lambda function. This may not match the
     *          checksum for the object stored in Amazon S3. Amazon S3 will perform validation of the checksum values
     *          only when the original <code>GetObject</code> request required checksum validation. For
     *          more information about checksums, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html">Checking object
     *             integrity</a> in the <i>Amazon S3 User Guide</i>.</p>
     *          <p>Only one checksum header can be specified at a time. If you supply multiple checksum
     *          headers, this request will fail.</p>
     */
    ChecksumSHA256?: string;
    /**
     * <p>Specifies whether an object stored in Amazon S3 is (<code>true</code>) or is not
     *             (<code>false</code>) a delete marker. </p>
     */
    DeleteMarker?: boolean;
    /**
     * <p>An opaque identifier assigned by a web server to a specific version of a resource found
     *          at a URL. </p>
     */
    ETag?: string;
    /**
     * <p>The date and time at which the object is no longer cacheable.</p>
     */
    Expires?: Date;
    /**
     * <p>If the object expiration is configured (see PUT Bucket lifecycle), the response includes
     *          this header. It includes the <code>expiry-date</code> and <code>rule-id</code> key-value
     *          pairs that provide the object expiration information. The value of the <code>rule-id</code>
     *          is URL-encoded. </p>
     */
    Expiration?: string;
    /**
     * <p>The date and time that the object was last modified.</p>
     */
    LastModified?: Date;
    /**
     * <p>Set to the number of metadata entries not returned in <code>x-amz-meta</code> headers.
     *          This can happen if you create metadata using an API like SOAP that supports more flexible
     *          metadata than the REST API. For example, using SOAP, you can create metadata whose values
     *          are not legal HTTP headers.</p>
     */
    MissingMeta?: number;
    /**
     * <p>A map of metadata to store with the object in S3.</p>
     */
    Metadata?: Record<string, string>;
    /**
     * <p>Indicates whether an object stored in Amazon S3 has Object Lock enabled. For more information
     *          about S3 Object Lock, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html">Object Lock</a>.</p>
     */
    ObjectLockMode?: ObjectLockMode | string;
    /**
     * <p>Indicates whether an object stored in Amazon S3 has an active legal hold.</p>
     */
    ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus | string;
    /**
     * <p>The date and time when Object Lock is configured to expire.</p>
     */
    ObjectLockRetainUntilDate?: Date;
    /**
     * <p>The count of parts this object has.</p>
     */
    PartsCount?: number;
    /**
     * <p>Indicates if request involves bucket that is either a source or destination in a
     *          Replication rule. For more information about S3 Replication, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html">Replication</a>.</p>
     */
    ReplicationStatus?: ReplicationStatus | string;
    /**
     * <p>If present, indicates that the requester was successfully charged for the
     *          request.</p>
     */
    RequestCharged?: RequestCharged | string;
    /**
     * <p>Provides information about object restoration operation and expiration time of the
     *          restored object copy.</p>
     */
    Restore?: string;
    /**
     * <p> The server-side encryption algorithm used when storing requested object in Amazon S3 (for
     *          example, AES256, <code>aws:kms</code>).</p>
     */
    ServerSideEncryption?: ServerSideEncryption | string;
    /**
     * <p>Encryption algorithm used if server-side encryption with a customer-provided encryption
     *          key was specified for object stored in Amazon S3.</p>
     */
    SSECustomerAlgorithm?: string;
    /**
     * <p> If present, specifies the ID of the Amazon Web Services Key Management Service (Amazon Web Services KMS) symmetric
     *          encryption customer managed key that was used for stored in Amazon S3 object. </p>
     */
    SSEKMSKeyId?: string;
    /**
     * <p> 128-bit MD5 digest of customer-provided encryption key used in Amazon S3 to encrypt data
     *          stored in S3. For more information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html">Protecting data
     *             using server-side encryption with customer-provided encryption keys
     *          (SSE-C)</a>.</p>
     */
    SSECustomerKeyMD5?: string;
    /**
     * <p>Provides storage class information of the object. Amazon S3 returns this header for all
     *          objects except for S3 Standard storage class objects.</p>
     *          <p>For more information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html">Storage Classes</a>.</p>
     */
    StorageClass?: StorageClass | string;
    /**
     * <p>The number of tags, if any, on the object.</p>
     */
    TagCount?: number;
    /**
     * <p>An ID used to reference a specific version of the object.</p>
     */
    VersionId?: string;
    /**
     * <p> Indicates whether the object stored in Amazon S3 uses an S3 bucket key for server-side
     *          encryption with Amazon Web Services KMS (SSE-KMS).</p>
     */
    BucketKeyEnabled?: boolean;
}
/**
 * @internal
 */
export declare const EncryptionFilterSensitiveLog: (obj: Encryption) => any;
/**
 * @internal
 */
export declare const S3LocationFilterSensitiveLog: (obj: S3Location) => any;
/**
 * @internal
 */
export declare const OutputLocationFilterSensitiveLog: (obj: OutputLocation) => any;
/**
 * @internal
 */
export declare const RestoreRequestFilterSensitiveLog: (obj: RestoreRequest) => any;
/**
 * @internal
 */
export declare const RestoreObjectRequestFilterSensitiveLog: (obj: RestoreObjectRequest) => any;
/**
 * @internal
 */
export declare const SelectObjectContentEventStreamFilterSensitiveLog: (obj: SelectObjectContentEventStream) => any;
/**
 * @internal
 */
export declare const SelectObjectContentOutputFilterSensitiveLog: (obj: SelectObjectContentOutput) => any;
/**
 * @internal
 */
export declare const SelectObjectContentRequestFilterSensitiveLog: (obj: SelectObjectContentRequest) => any;
/**
 * @internal
 */
export declare const UploadPartOutputFilterSensitiveLog: (obj: UploadPartOutput) => any;
/**
 * @internal
 */
export declare const UploadPartRequestFilterSensitiveLog: (obj: UploadPartRequest) => any;
/**
 * @internal
 */
export declare const UploadPartCopyOutputFilterSensitiveLog: (obj: UploadPartCopyOutput) => any;
/**
 * @internal
 */
export declare const UploadPartCopyRequestFilterSensitiveLog: (obj: UploadPartCopyRequest) => any;
/**
 * @internal
 */
export declare const WriteGetObjectResponseRequestFilterSensitiveLog: (obj: WriteGetObjectResponseRequest) => any;
                                                                        kes a dict |env| whose values are strings that can refer to other keys,
  for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
  env such that key2 is after key1 in L if env[key2] refers to env[key1].

  Throws an Exception in case of dependency cycles.
  """
    # Since environment variables can refer to other variables, the evaluation
    # order is important. Below is the logic to compute the dependency graph
    # and sort it.
    regex = re.compile(r"\$\{([a-zA-Z0-9\-_]+)\}")

    def GetEdges(node):
        # Use a definition of edges such that user_of_variable -> used_varible.
        # This happens to be easier in this case, since a variable's
        # definition contains all variables it references in a single string.
        # We can then reverse the result of the topological sort at the end.
        # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
        matches = {v for v in regex.findall(env[node]) if v in env}
        for dependee in matches:
            assert "${" not in dependee, "Nested variables not supported: " + dependee
        return matches

    try:
        # Topologically sort, and then reverse, because we used an edge definition
        # that's inverted from the expected result of this function (see comment
        # above).
        order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
        order.reverse()
        return order
    except gyp.common.CycleError as e:
        raise GypError(
            "Xcode environment variables are cyclically dependent: " + str(e.nodes)
        )


def GetSortedXcodeEnv(
    xcode_settings, built_products_dir, srcroot, configuration, additional_settings=None
):
    env = _GetXcodeEnv(
        xcode_settings, built_products_dir, srcroot, configuration, additional_settings
    )
    return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)]


def GetSpecPostbuildCommands(spec, quiet=False):
    """Returns the list of postbuilds explicitly defined on |spec|, in a form
  executable by a shell."""
    postbuilds = []
    for postbuild in spec.get("postbuilds", []):
        if not quiet:
            postbuilds.append(
                "echo POSTBUILD\\(%s\\) %s"
                % (spec["target_name"], postbuild["postbuild_name"])
            )
        postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild["action"]))
    return postbuilds


def _HasIOSTarget(targets):
    """Returns true if any target contains the iOS specific key
  IPHONEOS_DEPLOYMENT_TARGET."""
    for target_dict in targets.values():
        for config in target_dict["configurations"].values():
            if config.get("xcode_settings", {}).get("IPHONEOS_DEPLOYMENT_TARGET"):
                return True
    return False


def _AddIOSDeviceConfigurations(targets):
    """Clone all targets and append -iphoneos to the name. Configure these targets
  to build for iOS devices and use correct architectures for those builds."""
    for target_dict in targets.values():
        toolset = target_dict["toolset"]
        configs = target_dict["configurations"]
        for config_name, simulator_config_dict in dict(configs).items():
            iphoneos_config_dict = copy.deepcopy(simulator_config_dict)
            configs[config_name + "-iphoneos"] = iphoneos_config_dict
            configs[config_name + "-iphonesimulator"] = simulator_config_dict
            if toolset == "target":
                simulator_config_dict["xcode_settings"]["SDKROOT"] = "iphonesimulator"
                iphoneos_config_dict["xcode_settings"]["SDKROOT"] = "iphoneos"
    return targets


def CloneConfigurationForDeviceAndEmulator(target_dicts):
    """If |target_dicts| contains any iOS targets, automatically create -iphoneos
  targets for iOS device builds."""
    if _HasIOSTarget(target_dicts):
        return _AddIOSDeviceConfigurations(target_dicts)
    return target_dicts
                                                                                                                                                                                                D
                  P
                  d
                  p
                  v
                  
                   
                  
                  
                  
                  
                  
                                                       +      $            0      (                  ,                  0                  4                  8                  <                  @                  D                  H                  L                  P            !      T                  X                  \                  `                  d                  h                  l                  p                  t            $      x            j      |            s                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     #                  B                  [                  f                  h                                                                                                                                                                                                              $                  (                  ,                  0                  4                  8                  <                  @                  D                  H            y      L                  P                  T                   X                  \                  `                  d                  h                  l                  p            #      t            w      x            x      |            y                  {                  }                                                                        :                  J                  \                  k                  p                                                                                          9                  }                                                                                                                                                #                  #                  #                  #                   #                  !#                  *#                  #                  #                   #                  #                  #                  #                  #                  #                  #                  #                   #      $            $      (            $      ,            $      0            $      4            $      8            $      <            $      @            $      D            %      H             %      L            '%      P            )%      T            .%      X            3%      \            4%      `            5%      d            %      h            %      l            %      p            %      t            %      x            %      |            %                  %                   &                  &                  &                  _&                  `&                  e&                  &                  &                  &                  ('                  0'                  6'                  >'                  h'                  i'                  n'                  '                  '                  '                  '                  '                  '                  ^(                  _(                  a(                  c(                  h(                  (                  (                  (                  (                   (                  (                  (                  $)                  %)                  ')                  ))                  +)                   0)      $            )      (            )      ,            )      0            )      4            *      8            *      <            *      @             *      D            &*      H            v*      L            {*      P            *      T            *      X            *      \            *      `            *      d            *      h            '+      l            (+      p            *+      t            ,+      x            .+      |            3+                  4+                  >+                  B+                  I+                  K+                  P+                  k+                  p+                  w+                  x+                  |+                  -,                  .,                  0,                  5,                  =,                  @,                  G,                  P,                  Y,                  Z,                  a,                  h,                  k-                  o-                  p-                  r-                  t-                  v-                  {-                  -                  -                   -                  -                  -                  -                  _.                  `.                  b.                  d.                   f.      $            k.      (            .      ,            .      0            /      4            /      8            /      <            /      @            $/      D            (/      H            )/      L            0/      P            /      T            /      X            /      \            /      `            /      d            /      h            /      l            /      p            1      t            1      x             1      |            (1                  81                  a1                  p1                  w1                  y1                  1                  1                  1                  1                  1                  1                  1                  1                  1                  1                  1                  1                  1                   3                  '3                  -3                  /3                  43                  53                  63                  4                  4                  4                  4                  4                   4                  %4                   4                  4                  4                  4                  4                  4                  4                  4                    5      $            5      (            5      ,            5      0            5      4            5      8            5      <            5      @            	9      D            
9      H            9      L            
9      P            9      T            9      X            9      \            9      `            ?      d            ?      h            ?      l            ?      p            ?      t            @      x            @      |            @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  @                  RA                  XA                  ZA                  \A                  ^A                  `A                  eA                  A                  A                  A                  A                  A                  A                  B                  B                  B                  B                   B                  B                  B                  B                  B                  B                  B                  B                   B      $            C      (            C      ,            C      0            C      4            C      8            C      <            C      @            UE      D            `E      H            fE      L            nE      P            E      T            E      X            E      \            E      `            E      d            E      h            E      l            F      p            
F      t            F      x            F      |            ^F                  _F                  `F                  bF                  dF                  fF                  kF                  H                   H                  'H                  )H                  +H                  -H                  1H                  2H                  6H                  L                  L                  	L                  L                  
L                  L                  L                  L                  `L                  gL                  iL                  kL                  mL                  nL                  oL                  sL                  YO       	            ZO      	            [O      	            ]O      	            _O      	            aO      	            cO      	            hO      	            uQ       	            Q      $	            Q      (	            Q      ,	            Q      0	            Q      4	            Q      8	            Q      <	            Q      @	            
R      D	            R      H	            R      L	            R      P	            R      T	            R      X	            R      \	            R      `	            ^      d	            _      h	            _      l	                    p	                   t	                   x	                   |	                   	                   	                    	            =       	                    	            _       	            z       	                   	                  	                                                                                                                o%                           $             d+      (                     0             +      4                     <             +      @                     H             -      L                     T             2      X                     `             4      d                     l             ?      p                     x             ?      |                                  ?                                                                            	   Z                   <                   C                	   "                    	      $                   (          	   B      0             
&      4             e&      8          	          @             '      D             h(      H          	   *       P             (      T             0)      X          	   b       `             0      d             0      h          	         p             6      t             7      x          	                      B                   D                	   
                   E                   E                	                       ^                   ^                	   z                                                           p      (                     @             )                                                                                                                                                      8                    @                    H                   P                   p                    x                                                                                                                                                                                                                                                          (                  0                   P                   X            0      `            0       h                                                                   0                   '                                                       0                   @                                       P                  0                   @       0                   8            p      @            0       H                                  ,                           8                    P                     .symtab .strtab .shstrtab .note.gnu.build-id .note.Linux .rela.text .rela.init.text .rela.exit.text .rela.text.unlikely .rela__mcount_loc .rela.smp_locks .rodata.str1.8 .rodata.str1.1 .rela.rodata .modinfo .rela__param .rela.retpoline_sites .rela.return_sites .orc_unwind .rela.orc_unwind_ip __versions .rela__bug_table .rela__jump_table .rela.data .rela.exit.data .rela.init.data .rela__dyndbg .rela.static_call_sites .rela.gnu.linkonce.this_module .bss .comment .note.GNU-stack .BTF .gnu_debuglink                                                                                         @       $                              .                     d       <                              ?                            _                             :      @                     4      3                    J                     @`                                    E      @                     @      3                    Z                     %a      =                              U      @               `            3                    j                     ba                                   e      @               P            3   	                 ~                     c                                   y      @               P"           3                                         e      D                                    @               0'           3   
                       2               e      s                                  2               Cj                                                       @p      J                                    @               (     h      3                                         u                                                        w      P                                    @               0-            3                                         w                                           @               -            3                                          x                                          @               .           3                                        x      v                                                 n      	                                  @               4     9      3                    %                                                         5                                                        0     @               Xn     @      3                    F                    0                                    A     @               p           3                     X                          ,                              S     @               s            3   "                 c                                                        ^     @               @t            3   $                 s                                                        n     @               Xt            3   &                                            h                             ~     @               pt            3   (                                                                              @               x     0       3   *                                                         @                    @               x     0       3   ,                                     @                                         0               @      P                                                                                                                                                                                                                                          4                    	                                                                               x                                  0	*H
01
0	`He0	*H
1a0]080 10UDebian Secure Boot CA2(oe:B&C0	`He0
	*H
  }{e3(L	\y]CY\K
46#C10i|^;_vـx
ku냀z}H%xJG!Jh
siL}6;U-6L3ivmH2͇}vҵG=|M꺣g"6ݤKI']׻YNn,Ք#ΐ|~Iu̔ՙpEbego
TdXZLFF         ~Module signature appended~
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     밍할 때 문제가 될 수도 있습니다.\n\nTerminus 글꼴의 굵은 버전을 사용하고 싶으면 TerminusBold나 (프레임버퍼를 사용하는 경우) TerminusBoldVGA를 (기타 경우) 사용하십시오.
Extended_description-ku.utf-8: Di "VGA"ê de xuyakirineke dêrîn û qalikeke navîn a skrîptên navneteweyî heye. Di "Fixed"ê de xuyakirinên ji rêzê hene û qalikê wê yê skrîptên navneteweyî çêtir in. Dibe ku  "Terminus" ji te re bibe alîkar.\n\nEger tu guhertoyeke sitûr a curenivîsa Terminusê hilbijêrî, TerminusBold (eger frambufferekê bi kar bînî) an jî TerminusBoldVGAyê (wekî din) jî hilbijêre.
Extended_description-lo.utf-8: "VGA" ມີລັກສະນະແບບດັ້ງເດີມແລະມີຂະໜາດກາງ\n\nຖ້າທ່ານຕ້ອງການລຸ້ນໂຕໜາຂອງໂຕອັກສອນສະຖານນີໃຫ້ເລືອກຢ່າງໃດຢ່າງໜຶ່ງ
Extended_description-lt.utf-8: „VGA“ yra tradicinės išvaizdos ir turi pusę tarptautinių simbolių. „Fixed“ yra supaprastintos išvaizdos, bet turi daugiau tarptautinių simbolių. „Terminus“ mažiau vargina akis, nors kai kurie simboliai yra labai panašūs ir gali sukelti problemų programuotojams.\n\nJei norite naudoti pastorintą „Terminus“ šrifto variantą, pasirinkite „TerminusBold“ (jei naudojate kadrų buferį) arba „TerminusBoldVGA“ (jei nenaudojate).
Extended_description-lv.utf-8: "VGA" ir tradicionāls izskats un vidējs starptautisko rakstu nodrošinājums. "Fixed" ir vienkāršots izskats un labāks starptautisko skriptu nodrošinājums. "Terminus" var mazināt acu nogurumu, bet dažiem simboliem ir līdzīgs izskats, kas var būt neērti programmētājiem.\n\nJa vēlaties Terminus fonta treknraksta versiju, izvēlieties vai nu TerminusBold (ja izmantojat kadru buferi), vai TerminusBoldVGA (citādi).
Extended_description-mk.utf-8: "VGA" има традиционален изглед и средна покриеност за интернационални писма. "Fixed" има едноставен изглед и подобра покриеност за интернационални писма. "Terminus" може да помогне при умор на очите, иако некои симболи имаат сличен аспект кој што може да биде проблем за програмери.\n\nАко преферирате задебелена верзија на фонтот Terminus, изберете TerminusBold (ако користите framebuffer) или TerminusBoldVGA (ако не користите framebuffer).
Extended_description-ml.utf-8: "VGA" യ്ക്കു് പരമ്പരാഗത ഭംഗിയും അന്താരാഷ്ട്ര ലിപികള്‍ക്കു് ഇടത്തരം പിന്തുണയും ഉണ്ടു്. "Fixed" നു് ലാളിത്യവും അന്താരാഷ്ട്ര ലിപികള്‍ക്കുള്ള കൂടിയ പിന്തുണയും ഉണ്ടു്. "Terminus" കണ്ണിന്റെ ക്ഷീണം കുറയ്ക്കാന്‍ സഹായിച്ചേയ്ക്കാമെങ്കലും ചില ചിഹ്നങ്ങള്‍ ഒരു പോലായതിനാല്‍ പ്രോഗ്രാമ്മര്‍മാര്‍ക്കു് പ്രശ്നമായേയ്ക്കാം.\n\nനിങ്ങള്‍ക്കു് ടെര്‍മിനസ് അക്ഷരസഞ്ചയം വേണമെങ്കില്‍ TerminusBold (ഫ്രെയിംബഫര്‍ ഉപയോഗിയ്ക്കുകയാണെങ്കില്‍) അല്ലെങ്കില്‍ TerminusBoldVGA (മറ്റുള്ളവയ്ക്കു്) എന്നിവയിലേതെങ്കിലും തെരഞ്ഞെടുക്കുക.
Extended_description-mr.utf-8: "VGA" पारंपरिक दिसतो आणि आंतरराष्ट्रीय लिप्यांचा त्यात मध्यम समावेश असतो. "Fixed" साधा दिसतो आणि आंतरराष्ट्रीय लिप्यांचा त्यात चांगला समावेश असतो. "Terminus" डोळ्यांवरील ताण कमी करू शकतो, पण त्यात काही चिन्हे एकसमान दिसत असल्याने आज्ञावलीकारांना समस्या निर्माण होऊ शकतात.\n\nटर्मिनस टंकमुद्रांची ठळक आवृत्ती हवी असल्यास, एकतरTerminusBold (तुम्ही फ्रेमबफर वापरत असल्यास) किंवा TerminusBoldVGA (अन्यथा) निवडा.
Extended_description-nb.utf-8: «VGA» har et tradisjonelt utseende og har medium dekning av internasjonale tegn. «Fixed» har et enkelt utseende og har bedre dekning av internasjonale tegn. «Terminus» kan redusere øyetrøtthet, selvom noen symbol har lignende aspekt som kan skape problemer for programmere.\n\nHvis du foretrekker en fet versjon av Terminus-skriften, velg enten TerminusBold (hvis du bruker framebuffer) eller TerminusBoldVGA (ellers).
Extended_description-ne.utf-8: "VGA" को पुरानो देखावट र आन्तरिक स्क्रिप्टको मध्यम कभरेज । "स्थिर" को सरल देखावट र आन्तरिक स्क्रिप्टको उचित कभरेज । कार्यक्रम बनाउनेको लागि समस्या हुनसक्ने उस्तै प्रकारका केहि संकेत हरू बनाउनलाई "टरमिनस"ले दृष्टि घटाउन सहयोग पुर्याउन सक्छ ।\n\nयदि तपाईँ टर्मिनस फन्ट को बोल्ड संस्करण चाहानुहुन्छ भने, कि त TerminusBold (यदि तपाईँ फ्रेम बफर प्रयोग गर्नुहुन्छ भने) कि त TerminusBoldVGA (अन्य तरिकाद्वारा) छनौट गर्नुहोस् ।
Extended_description-nl.utf-8: "VGA" oogt traditioneel en biedt gemiddelde dekking voor internationale karaktersets. "Fixed" oogt eenvoudiger en biedt een betere dekking voor internationale karaktersets."Terminus" kan helpen met het verminderen van oogmoeheid maar heeft als nadeel dat sommige symbolen erg op elkaar lijken, hetgeen problemen kan opleveren voor ontwikkelaars.\n\nAls u de vetgedrukte versie van het lettertype Terminus verkiest, selecteer dan TerminusBold als u een framebuffer gebruikt, of anders TerminusBoldVGA.
Extended_description-nn.utf-8: «VGA» har ein tradisjonell utsjånad og middels dekning av internasjonale teikn. «Fixed» har ein enkel utsjånad og betre støtte for internasjonale teikn. «Terminus» kan gjera til at du ikkje så fort vert sliten i auga, men nokre teikn kan vera ganske like og såleis skapa problem for utviklarar.\n\nViss du føretrekk ein halvfeit versjon av Terminus-skrifta, vel du anten TerminusBold (viss du brukar mellomlagring av bilete) eller TerminusBoldVGA (viss ikkje).
Extended_description-no.utf-8: «VGA» har et tradisjonelt utseende og har medium dekning av internasjonale tegn. «Fixed» har et enkelt utseende og har bedre dekning av internasjonale tegn. «Terminus» kan redusere øyetrøtthet, selvom noen symbol har lignende aspekt som kan skape problemer for programmere.\n\nHvis du foretrekker en fet versjon av Terminus-skriften, velg enten TerminusBold (hvis du bruker framebuffer) eller TerminusBoldVGA (ellers).
Extended_description-oc.utf-8: « VGA » correspond a l'aparéncia tradicionala, possedís una cobertura mejana d'escripts intpackage ExtUtils::MM_Any;

use strict;
use warnings;
our $VERSION = '7.64';
$VERSION =~ tr/_//d;

use Carp;
use File::Spec;
use File::Basename;
BEGIN { our @ISA = qw(File::Spec); }

# We need $Verbose
use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);

use ExtUtils::MakeMaker::Config;


# So we don't have to keep calling the methods over and over again,
# we have these globals to cache the values.  Faster and shrtr.
my $Curdir  = __PACKAGE__->curdir;
#my $Updir   = __PACKAGE__->updir;

my $METASPEC_URL = 'https://metacpan.org/pod/CPAN::Meta::Spec';
my $METASPEC_V = 2;

=head1 NAME

ExtUtils::MM_Any - Platform-agnostic MM methods

=head1 SYNOPSIS

  FOR INTERNAL USE ONLY!

  package ExtUtils::MM_SomeOS;

  # Temporarily, you have to subclass both.  Put MM_Any first.
  require ExtUtils::MM_Any;
  require ExtUtils::MM_Unix;
  @ISA = qw(ExtUtils::MM_Any ExtUtils::Unix);

=head1 DESCRIPTION

B<FOR INTERNAL USE ONLY!>

ExtUtils::MM_Any is a superclass for the ExtUtils::MM_* set of
modules.  It contains methods which are either inherently
cross-platform or are written in a cross-platform manner.

Subclass off of ExtUtils::MM_Any I<and> L<ExtUtils::MM_Unix>.  This is a
temporary solution.

B<THIS MAY BE TEMPORARY!>


=head1 METHODS

Any methods marked I<Abstract> must be implemented by subclasses.


=head2 Cross-platform helper methods

These are methods which help writing cross-platform code.



=head3 os_flavor  I<Abstract>

    my @os_flavor = $mm->os_flavor;

@os_flavor is the style of operating system this is, usually
corresponding to the MM_*.pm file we're using.

The first element of @os_flavor is the major family (ie. Unix,
Windows, VMS, OS/2, etc...) and the rest are sub families.

Some examples:

    Cygwin98       ('Unix',  'Cygwin', 'Cygwin9x')
    Windows        ('Win32')
    Win98          ('Win32', 'Win9x')
    Linux          ('Unix',  'Linux')
    MacOS X        ('Unix',  'Darwin', 'MacOS', 'MacOS X')
    OS/2           ('OS/2')

This is used to write code for styles of operating system.
See os_flavor_is() for use.


=head3 os_flavor_is

    my $is_this_flavor = $mm->os_flavor_is($this_flavor);
    my $is_this_flavor = $mm->os_flavor_is(@one_of_these_flavors);

Checks to see if the current operating system is one of the given flavors.

This is useful for code like:

    if( $mm->os_flavor_is('Unix') ) {
        $out = `foo 2>&1`;
    }
    else {
        $out = `foo`;
    }

=cut

sub os_flavor_is {
    my $self = shift;
    my %flavors = map { ($_ => 1) } $self->os_flavor;
    return (grep { $flavors{$_} } @_) ? 1 : 0;
}


=head3 can_load_xs

    my $can_load_xs = $self->can_load_xs;

Returns true if we have the ability to load XS.

This is important because miniperl, used to build XS modules in the
core, can not load XS.

=cut

sub can_load_xs {
    return defined &DynaLoader::boot_DynaLoader ? 1 : 0;
}


=head3 can_run

  use ExtUtils::MM;
  my $runnable = MM->can_run($Config{make});

If called in a scalar context it will return the full path to the binary
you asked for if it was found, or C<undef> if it was not.

If called in a list context, it will return a list of the full paths to instances
of the binary where found in C<PATH>, or an empty list if it was not found.

Copied from L<IPC::Cmd|IPC::Cmd/"$path = can_run( PROGRAM );">, but modified into
a method (and removed C<$INSTANCES> capability).

=cut

sub can_run {
    my ($self, $command) = @_;

    # a lot of VMS executables have a symbol defined
    # check those first
    if ( $^O eq 'VMS' ) {
        require VMS::DCLsym;
        my $syms = VMS::DCLsym->new;
        return $command if scalar $syms->getsym( uc $command );
    }

    my @possibles;

    if( File::Spec->file_name_is_absolute($command) ) {
        return $self->maybe_command($command);

    } else {
        for my $dir (
            File::Spec->path,
            File::Spec->curdir
        ) {
            next if ! $dir || ! -d $dir;
            my $abs = File::Spec->catfile($self->os_flavor_is('Win32') ? Win32::GetShortPathName( $dir ) : $dir, $command);
            push @possibles, $abs if $abs = $self->maybe_command($abs);
        }
    }
    return @possibles if wantarray;
    return shift @possibles;
}


=head3 can_redirect_error

  $useredirect = MM->can_redirect_error;

True if on an OS where qx operator (or backticks) can redirect C<STDERR>
onto C<STDOUT>.

=cut

sub can_redirect_error {
  my $self = shift;
  $self->os_flavor_is('Unix')
      or ($self->os_flavor_is('Win32') and !$self->os_flavor_is('Win9x'))
      or $self->os_flavor_is('OS/2')
}


=head3 is_make_type

    my $is_dmake = $self->is_make_type('dmake');

Returns true if C<< $self->make >> is the given type; possibilities are:

  gmake    GNU make
  dmake
  nmake
  bsdmake  BSD pmake-derived

=cut

my %maketype2true;
# undocumented - so t/cd.t can still do its thing
sub _clear_maketype_cache { %maketype2true = () }

sub is_make_type {
    my($self, $type) = @_;
    return $maketype2true{$type} if defined $maketype2true{$type};
    (undef, undef, my $make_basename) = $self->splitpath($self->make);
    return $maketype2true{$type} = 1
        if $make_basename =~ /\b$type\b/i; # executable's filename
    return $maketype2true{$type} = 0
        if $make_basename =~ /\b[gdn]make\b/i; # Never fall through for dmake/nmake/gmake
    # now have to run with "-v" and guess
    my $redirect = $self->can_redirect_error ? '2>&1' : '';
    my $make = $self->make || $self->{MAKE};
    my $minus_v = `"$make" -v $redirect`;
    return $maketype2true{$type} = 1
        if $type eq 'gmake' and $minus_v =~ /GNU make/i;
    return $maketype2true{$type} = 1
        if $type eq 'bsdmake'
      and $minus_v =~ /^usage: make \[-BeikNnqrstWwX\]/im;
    $maketype2true{$type} = 0; # it wasn't whatever you asked
}


=head3 can_dep_space

    my $can_dep_space = $self->can_dep_space;

Returns true if C<make> can handle (probably by quoting)
dependencies that contain a space. Currently known true for GNU make,
false for BSD pmake derivative.

=cut

my $cached_dep_space;
sub can_dep_space {
    my $self = shift;
    return $cached_dep_space if defined $cached_dep_space;
    return $cached_dep_space = 1 if $self->is_make_type('gmake');
    return $cached_dep_space = 0 if $self->is_make_type('dmake'); # only on W32
    return $cached_dep_space = 0 if $self->is_make_type('bsdmake');
    return $cached_dep_space = 0; # assume no
}


=head3 quote_dep

  $text = $mm->quote_dep($text);

Method that protects Makefile single-value constants (mainly filenames),
so that make will still treat them as single values even if they
inconveniently have spaces in. If the make program being used cannot
achieve such protection and the given text would need it, throws an
exception.

=cut

sub quote_dep {
    my ($self, $arg) = @_;
    die <<EOF if $arg =~ / / and not $self->can_dep_space;
Tried to use make dependency with space for make that can't:
  '$arg'
EOF
    $arg =~ s/( )/\\$1/g; # how GNU make does it
    return $arg;
}


=head3 split_command

    my @cmds = $MM->split_command($cmd, @args);

Most OS have a maximum command length they can execute at once.  Large
modules can easily generate commands well past that limit.  Its
necessary to split long commands up into a series of shorter commands.

C<split_command> will return a series of @cmds each processing part of
the args.  Collectively they will process all the arguments.  Each
individual line in @cmds will not be longer than the
$self->max_exec_len being careful to take into account macro expansion.

$cmd should include any switches and repeated initial arguments.

If no @args are given, no @cmds will be returned.

Pairs of arguments will always be preserved in a single command, this
is a heuristic for things like pm_to_blib and pod2man which work on
pairs of arguments.  This makes things like this safe:

    $self->split_command($cmd, %pod2man);


=cut

sub split_command {
    my($self, $cmd, @args) = @_;

    my @cmds = ();
    return(@cmds) unless @args;

    # If the command was given as a here-doc, there's probably a trailing
    # newline.
    chomp $cmd;

    # set aside 30% for macro expansion.
    my $len_left = int($self->max_exec_len * 0.70);
    $len_left -= length $self->_expand_macros($cmd);

    do {
        my $arg_str = '';
        my @next_args;
        while( @next_args = splice(@args, 0, 2) ) {
            # Two at a time to preserve pairs.
            my $next_arg_str = "\t  ". join ' ', @next_args, "\n";

            if( !length $arg_str ) {
                $arg_str .= $next_arg_str
            }
            elsif( length($arg_str) + length($next_arg_str) > $len_left ) {
                unshift @args, @next_args;
                last;
            }
            else {
                $arg_str .= $next_arg_str;
            }
        }
        chop $arg_str;

        push @cmds, $self->escape_newlines("$cmd \n$arg_str");
    } while @args;

    return @cmds;
}


sub _expand_macros {
    my($self, $cmd) = @_;

    $cmd =~ s{\$\((\w+)\)}{
        defined $self->{$1} ? $self->{$1} : "\$($1)"
    }e;
    return $cmd;
}


=head3 make_type

Returns a suitable string describing the type of makefile being written.

=cut

# override if this isn't suitable!
sub make_type { return 'Unix-style'; }


=head3 stashmeta

    my @recipelines = $MM->stashmeta($text, $file);

Generates a set of C<@recipelines> which will result in the literal
C<$text> ending up in literal C<$file> when the recipe is executed. Call
it once, with all the text you want in C<$file>. Make macros will not
be expanded, so the locations will be fixed at configure-time, not
at build-time.

=cut

sub stashmeta {
    my($self, $text, $file) = @_;
    $self->echo($text, $file, { allow_variables => 0, append => 0 });
}


=head3 echo

    my @commands = $MM->echo($text);
    my @commands = $MM->echo($text, $file);
    my @commands = $MM->echo($text, $file, \%opts);

Generates a set of @commands which print the $text to a $file.

If $file is not given, output goes to STDOUT.

If $opts{append} is true the $file will be appended to rather than
overwritten.  Default is to overwrite.

If $opts{allow_variables} is true, make variables of the form
C<$(...)> will not be escaped.  Other C<$> will.  Default is to escape
all C<$>.

Example of use:

    my $make = join '', map "\t$_\n", $MM->echo($text, $file);

=cut

sub echo {
    my($self, $text, $file, $opts) = @_;

    # Compatibility with old options
    if( !ref $opts ) {
        my $append = $opts;
        $opts = { append => $append || 0 };
    }
    $opts->{allow_variables} = 0 unless defined $opts->{allow_variables};

    my $ql_opts = { allow_variables => $opts->{allow_variables} };
    my @cmds = map { '$(NOECHO) $(ECHO) '.$self->quote_literal($_, $ql_opts) }
               split /\n/, $text;
    if( $file ) {
        my $redirect = $opts->{append} ? '>>' : '>';
        $cmds[0] .= " $redirect $file";
        $_ .= " >> $file" foreach @cmds[1..$#cmds];
    }

    return @cmds;
}


=head3 wraplist

  my $args = $mm->wraplist(@list);

Takes an array of items and turns them into a well-formatted list of
arguments.  In most cases this is simply something like:

    FOO \
    BAR \
    BAZ

=cut

sub wraplist {
    my $self = shift;
    return join " \\\n\t", @_;
}


=head3 maketext_filter

    my $filter_make_text = $mm->maketext_filter($make_text);

The text of the Makefile is run through this method before writing to
disk.  It allows systems a chance to make portability fixes to the
Makefile.

By default it does nothing.

This method is protected and not intended to be called outside of
MakeMaker.

=cut

sub maketext_filter { return $_[1] }


=head3 cd  I<Abstract>

  my $subdir_cmd = $MM->cd($subdir, @cmds);

This will generate a make fragment which runs the @cmds in the given
$dir.  The rough equivalent to this, except cross platform.

  cd $subdir && $cmd

Currently $dir can only go down one level.  "foo" is fine.  "foo/bar" is
not.  "../foo" is right out.

The resulting $subdir_cmd has no leading tab nor trailing newline.  This
makes it easier to embed in a make string.  For example.

      my $make = sprintf <<'CODE', $subdir_cmd;
  foo :
      $(ECHO) what
      %s
      $(ECHO) mouche
  CODE


=head3 oneliner  I<Abstract>

  my $oneliner = $MM->oneliner($perl_code);
  my $oneliner = $MM->oneliner($perl_code, \@switches);

This will generate a perl one-liner safe for the particular platform
you're on based on the given $perl_code and @switches (a -e is
assumed) suitable for using in a make target.  It will use the proper
shell quoting and escapes.

$(PERLRUN) will be used as perl.

Any newlines in $perl_code will be escaped.  Leading and trailing
newlines will be stripped.  Makes this idiom much easier:

    my $code = $MM->oneliner(<<'CODE', [...switches...]);
some code here
another line here
CODE

Usage might be something like:

    # an echo emulation
    $oneliner = $MM->oneliner('print "Foo\n"');
    $make = '$oneliner > somefile';

Dollar signs in the $perl_code will be protected from make using the
C<quote_literal> method, unless they are recognised as being a make
variable, C<$(varname)>, in which case they will be left for make
to expand. Remember to quote make macros else it might be used as a
bareword. For example:

    # Assign the value of the $(VERSION_FROM) make macro to $vf.
    $oneliner = $MM->oneliner('$vf = "$(VERSION_FROM)"');

Its currently very simple and may be expanded sometime in the figure
to include more flexible code and switches.


=head3 quote_literal  I<Abstract>

    my $safe_text = $MM->quote_literal($text);
    my $safe_text = $MM->quote_literal($text, \%options);

This will quote $text so it is interpreted literally in the shell.

For example, on Unix this would escape any single-quotes in $text and
put single-quotes around the whole thing.

If $options{allow_variables} is true it will leave C<'$(FOO)'> make
variables untouched.  If false they will be escaped like any other
C<$>.  Defaults to true.

=head3 escape_dollarsigns

    my $escaped_text = $MM->escape_dollarsigns($text);

Escapes stray C<$> so they are not interpreted as make variables.

It lets by C<$(...)>.

=cut

sub escape_dollarsigns {
    my($self, $text) = @_;

    # Escape dollar signs which are not starting a variable
    $text =~ s{\$ (?!\() }{\$\$}gx;

    return $text;
}


=head3 escape_all_dollarsigns

    my $escaped_text = $MM->escape_all_dollarsigns($text);

Escapes all C<$> so they are not interpreted as make variables.

=cut

sub escape_all_dollarsigns {
    my($self, $text) = @_;

    # Escape dollar signs
    $text =~ s{\$}{\$\$}gx;

    return $text;
}


=head3 escape_newlines  I<Abstract>

    my $escaped_text = $MM->escape_newlines($text);

Shell escapes newlines in $text.


=head3 max_exec_len  I<Abstract>

    my $max_exec_len = $MM->max_exec_len;

Calculates the maximum command size the OS can exec.  Effectively,
this is the max size of a shell command line.

=for _private
$self->{_MAX_EXEC_LEN} is set by this method, but only for testing purposes.


=head3 make

    my $make = $MM->make;

Returns the make variant we're generating the Makefile for.  This attempts
to do some normalization on the information from %Config or the user.

=cut

sub make {
    my $self = shift;

    my $make = lc $self->{MAKE};

    # Truncate anything like foomake6 to just foomake.
    $make =~ s/^(\w+make).*/$1/;

    # Turn gnumake into gmake.
    $make =~ s/^gnu/g/;

    return $make;
}


=head2 Targets

These are methods which produce make targets.


=head3 all_target

Generate the default target 'all'.

=cut

sub all_target {
    my $self = shift;

    return <<'MAKE_EXT';
all :: pure_all
	$(NOECHO) $(NOOP)
MAKE_EXT

}


=head3 blibdirs_target

    my $make_frag = $mm->blibdirs_target;

Creates the blibdirs target which creates all the directories we use
in blib/.

The blibdirs.ts target is deprecated.  Depend on blibdirs instead.


=cut

sub _xs_list_basenames {
    my ($self) = @_;
    map { (my $b = $_) =~ s/\.xs$//; $b } sort keys %{ $self->{XS} };
}

sub blibdirs_target {
    my $self = shift;

    my @dirs = map { uc "\$(INST_$_)" } qw(libdir archlib
                                           autodir archautodir
                                           bin script
                                           man1dir man3dir
                                          );
    if ($self->{XSMULTI}) {
        for my $ext ($self->_xs_list_basenames) {
            my ($v, $d, $f) = File::Spec->splitpath($ext);
            my @d = File::Spec->splitdir($d);
            shift @d if $d[0] eq 'lib';
            push @dirs, $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
	}
    }

    my @exists = map { $_.'$(DFSEP).exists' } @dirs;

    my $make = sprintf <<'MAKE', join(' ', @exists);
blibdirs : %s
	$(NOECHO) $(NOOP)

# Backwards compat with 6.18 through 6.25
blibdirs.ts : blibdirs
	$(NOECHO) $(NOOP)

MAKE

    $make .= $self->dir_target(@dirs);

    return $make;
}


=head3 clean (o)

Defines the clean target.

=cut

sub clean {
# --- Cleanup and Distribution Sections ---

    my($self, %attribs) = @_;
    my @m;
    push(@m, '
# Delete temporary files but do not touch installed files. We don\'t delete
# the Makefile here so a later make realclean still has a makefile to use.

clean :: clean_subdirs
');

    my @files = sort values %{$self->{XS}}; # .c files from *.xs files
    push @files, map {
	my $file = $_;
	map { $file.$_ } $self->{OBJ_EXT}, qw(.def _def.old .bs .bso .exp .base);
    } $self->_xs_list_basenames;
    my @dirs  = qw(blib);

    # Normally these are all under blib but they might have been
    # redefined.
    # XXX normally this would be a good idea, but the Perl core sets
    # INST_LIB = ../../lib rather than actually installing the files.
    # So a "make clean" in an ext/ directory would blow away lib.
    # Until the core is adjusted let's leave this out.
#     push @dirs, qw($(INST_ARCHLIB) $(INST_LIB)
#                    $(INST_BIN) $(INST_SCRIPT)
#                    $(INST_MAN1DIR) $(INST_MAN3DIR)
#                    $(INST_LIBDIR) $(INST_ARCHLIBDIR) $(INST_AUTODIR)
#                    $(INST_STATIC) $(INST_DYNAMIC)
#                 );


    if( $attribs{FILES} ) {
        # Use @dirs because we don't know what's in here.
        push @dirs, ref $attribs{FILES}                ?
                        @{$attribs{FILES}}             :
                        split /\s+/, $attribs{FILES}   ;
    }

    push(@files, qw[$(MAKE_APERL_FILE)
                    MYMETA.json MYMETA.yml perlmain.c tmon.out mon.out so_locations
                    blibdirs.ts pm_to_blib pm_to_blib.ts
                    *$(OBJ_EXT) *$(LIB_EXT) perl.exe perl perl$(EXE_EXT)
                    $(BOOTSTRAP) $(BASEEXT).bso
                    $(BASEEXT).def lib$(BASEEXT).def
                    $(BASEEXT).exp $(BASEEXT).x
                   ]);

    push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'));
    push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.ld'));

    # core files
    if ($^O eq 'vos') {
        push(@files, qw[perl*.kp]);
    }
    else {
        push(@files, qw[core core.*perl.*.? *perl.core]);
    }

    push(@files, map { "core." . "[0-9]"x$_ } (1..5));

    # OS specific things to clean up.  Use @dirs since we don't know
    # what might be in here.
    push @dirs, $self->extra_clean_files;

    # Occasionally files are repeated several times from different sources
    { my(%f) = map { ($_ => 1) } @files; @files = sort keys %f; }
    { my(%d) = map { ($_ => 1) } @dirs;  @dirs  = sort keys %d; }

    push @m, map "\t$_\n", $self->split_command('- $(RM_F)',  @files);
    push @m, map "\t$_\n", $self->split_command('- $(RM_RF)', @dirs);

    # Leave Makefile.old around for realclean
    push @m, <<'MAKE';
	  $(NOECHO) $(RM_F) $(MAKEFILE_OLD)
	- $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)
MAKE

    push(@m, "\t$attribs{POSTOP}\n")   if $attribs{POSTOP};

    join("", @m);
}


=head3 clean_subdirs_target

  my $make_frag = $MM->clean_subdirs_target;

Returns the clean_subdirs target.  This is used by the clean target to
call clean on any subdirectories which contain Makefiles.

=cut

sub clean_subdirs_target {
    my($self) = shift;

    # No subdirectories, no cleaning.
    return <<'NOOP_FRAG' unless @{$self->{DIR}};
clean_subdirs :
	$(NOECHO) $(NOOP)
NOOP_FRAG


    my $clean = "clean_subdirs :\n";

    for my $dir (@{$self->{DIR}}) {
        my $subclean = $self->oneliner(sprintf <<'CODE', $dir);
exit 0 unless chdir '%s';  system '$(MAKE) clean' if -f '$(FIRST_MAKEFILE)';
CODE

        $clean .= "\t$subclean\n";
    }

    return $clean;
}


=head3 dir_target

    my $make_frag = $mm->dir_target(@directories);

Generates targets to create the specified directories and set its
permission to PERM_DIR.

Because depending on a directory to just ensure it exists doesn't work
too well (the modified time changes too often) dir_target() creates a
.exists file in the created directory.  It is this you should depend on.
For portability purposes you should use the $(DIRFILESEP) macro rather
than a '/' to separate the directory from the file.

    yourdirectory$(DIRFILESEP).exists

=cut

sub dir_target {
    my($self, @dirs) = @_;

    my $make = '';
    foreach my $dir (@dirs) {
        $make .= sprintf <<'MAKE', ($dir) x 4;
%s$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) %s
	$(NOECHO) $(CHMOD) $(PERM_DIR) %s
	$(NOECHO) $(TOUCH) %s$(DFSEP).exists

MAKE

    }

    return $make;
}


=head3 distdir

Defines the scratch directory target that will hold the distribution
before tar-ing (or shar-ing).

=cut

# For backwards compatibility.
*dist_dir = *distdir;

sub distdir {
    my($self) = shift;

    my $meta_target = $self->{NO_META} ? '' : 'distmeta';
    my $sign_target = !$self->{SIGN}   ? '' : 'distsignature';

    return sprintf <<'MAKE_FRAG', $meta_target, $sign_target;
create_distdir :
	$(RM_RF) $(DISTVNAME)
	$(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \
		-e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"

distdir : create_distdir %s %s
	$(NOECHO) $(NOOP)

MAKE_FRAG

}


=head3 dist_test

Defines a target that produces the distribution in the
scratch directory, and runs 'perl Makefile.PL; make ;make test' in that
subdirectory.

=cut

sub dist_test {
    my($self) = shift;

    my $mpl_args = join " ", map qq["$_"], @ARGV;

    my $test = $self->cd('$(DISTVNAME)',
                         '$(ABSPERLRUN) Makefile.PL '.$mpl_args,
                         '$(MAKE) $(PASTHRU)',
                         '$(MAKE) test $(PASTHRU)'
                        );

    return sprintf <<'MAKE_FRAG', $test;
disttest : distdir
	%s

MAKE_FRAG


}


=head3 xs_dlsyms_arg

Returns command-line arg(s) to linker for file listing dlsyms to export.
Defaults to returning empty string, can be overridden by e.g. AIX.

=cut

sub xs_dlsyms_arg {
    return '';
}

=head3 xs_dlsyms_ext

Returns file-extension for C<xs_make_dlsyms> method's output file,
including any "." character.

=cut

sub xs_dlsyms_ext {
    die "Pure virtual method";
}

=head3 xs_dlsyms_extra

Returns any extra text to be prepended to the C<$extra> argument of
C<xs_make_dlsyms>.

=cut

sub xs_dlsyms_extra {
    '';
}

=head3 xs_dlsyms_iterator

Iterates over necessary shared objects, calling C<xs_make_dlsyms> method
for each with appropriate arguments.

=cut

sub xs_dlsyms_iterator {
    my ($self, $attribs) = @_;
    if ($self->{XSMULTI}) {
        my @m;
        for my $ext ($self->_xs_list_basenames) {
            my @parts = File::Spec->splitdir($ext);
            shift @parts if $parts[0] eq 'lib';
            my $name = join '::', @parts;
            push @m, $self->xs_make_dlsyms(
                $attribs,
                $ext . $self->xs_dlsyms_ext,
                "$ext.xs",
                $name,
                $parts[-1],
                {}, [], {}, [],
                $self->xs_dlsyms_extra . q!, 'FILE' => ! . neatvalue($ext),
            );
        }
        return join "\n", @m;
    } else {
        return $self->xs_make_dlsyms(
            $attribs,
            $self->{BASEEXT} . $self->xs_dlsyms_ext,
            'Makefile.PL',
            $self->{NAME},
            $self->{DLBASE},
            $attribs->{DL_FUNCS} || $self->{DL_FUNCS} || {},
            $attribs->{FUNCLIST} || $self->{FUNCLIST} || [],
            $attribs->{IMPORTS} || $self->{IMPORTS} || {},
            $attribs->{DL_VARS} || $self->{DL_VARS} || [],
            $self->xs_dlsyms_extra,
        );
    }
}

=head3 xs_make_dlsyms

    $self->xs_make_dlsyms(
        \%attribs, # hashref from %attribs in caller
        "$self->{BASEEXT}.def", # output file for Makefile target
        'Makefile.PL', # dependency
        $self->{NAME}, # shared object's "name"
        $self->{DLBASE}, # last ::-separated part of name
        $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}, # various params
        $attribs{FUNCLIST} || $self->{FUNCLIST} || [],
        $attribs{IMPORTS} || $self->{IMPORTS} || {},
        $attribs{DL_VARS} || $self->{DL_VARS} || [],
        # optional extra param that will be added as param to Mksymlists
    );

Utility method that returns Makefile snippet to call C<Mksymlists>.

=cut

sub xs_make_dlsyms {
    my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
    my @m = (
     "\n$target: $dep\n",
     q!	$(PERLRUN) -MExtUtils::Mksymlists \\
     -e "Mksymlists('NAME'=>\"!, $name,
     q!\", 'DLBASE' => '!,$dlbase,
     # The above two lines quoted differently to work around
     # a bug in the 4DOS/4NT command line interpreter.  The visible
     # result of the bug was files named q('extension_name',) *with the
     # single quotes and the comma* in the extension build directories.
     q!', 'DL_FUNCS' => !,neatvalue($funcs),
     q!, 'FUNCLIST' => !,neatvalue($funclist),
     q!, 'IMPORTS' => !,neatvalue($imports),
     q!, 'DL_VARS' => !, neatvalue($vars)
    );
    push @m, $extra if defined $extra;
    push @m, qq!);"\n!;
    join '', @m;
}

=head3 dynamic (o)

Defines the dynamic target.

=cut

sub dynamic {
# --- Dynamic Loading Sections ---

    my($self) = shift;
    '
dynamic :: $(FIRST_MAKEFILE) config $(INST_BOOT) $(INST_DYNAMIC)
	$(NOECHO) $(NOOP)
';
}


=head3 makemakerdflt_target

  my $make_frag = $mm->makemakerdflt_target

Returns a make fragment with the makemakerdeflt_target specified.
This target is the first target in the Makefile, is the default target
and simply points off to 'all' just in case any make variant gets
confused or something gets snuck in before the real 'all' target.

=cut

sub makemakerdflt_target {
    return <<'MAKE_FRAG';
makemakerdflt : all
	$(NOECHO) $(NOOP)
MAKE_FRAG

}


=head3 manifypods_target

  my $manifypods_target = $self->manifypods_target;

Generates the manifypods target.  This target generates man pages from
all POD files in MAN1PODS and MAN3PODS.

=cut

sub manifypods_target {
    my($self) = shift;

    my $man1pods      = '';
    my $man3pods      = '';
    my $dependencies  = '';

    # populate manXpods & dependencies:
    foreach my $name (sort keys %{$self->{MAN1PODS}}, sort keys %{$self->{MAN3PODS}}) {
        $dependencies .= " \\\n\t$name";
    }

    my $manify = <<END;
manifypods : pure_all config $dependencies
END

    my @man_cmds;
    foreach my $num (qw(1 3)) {
        my $pods = $self->{"MAN${num}PODS"};
        my $p2m = sprintf <<'CMD', "\$(MAN${num}EXT)", "$]" > 5.008 ? " -u" : "";
	$(NOECHO) $(POD2MAN) --section=%s --perm_rw=$(PERM_RW)%s
CMD
        push @man_cmds, $self->split_command($p2m, map {($_,$pods->{$_})} sort keys %$pods);
    }

    $manify .= "\t\$(NOECHO) \$(NOOP)\n" unless @man_cmds;
    $manify .= join '', map { "$_\n" } @man_cmds;

    return $manify;
}

{
    my $has_cpan_meta;
    sub _has_cpan_meta {
        return $has_cpan_meta if defined $has_cpan_meta;
        return $has_cpan_meta = !!eval {
            require CPAN::Meta;
            CPAN::Meta->VERSION(2.112150);
            1;
        };
    }
}

=head3 metafile_target

    my $target = $mm->metafile_target;

Generate the metafile target.

Writes the file META.yml (YAML encoded meta-data) and META.json
(JSON encoded meta-data) about the module in the distdir.
The format follows Module::Build's as closely as possible.

=cut

sub metafile_target {
    my $self = shift;
    return <<'MAKE_FRAG' if $self->{NO_META} or ! _has_cpan_meta();
metafile :
	$(NOECHO) $(NOOP)
MAKE_FRAG

    my $metadata   = $self->metafile_data(
        $self->{META_ADD}   || {},
        $self->{META_MERGE} || {},
    );

    my $meta = $self->_fix_metadata_before_conversion( $metadata );

    my @write_metayml = $self->stashmeta(
      $meta->as_string({version => "1.4"}), 'META_new.yml'
    );
    my @write_metajson = $self->stashmeta(
      $meta->as_string({version => "2.0"}), 'META_new.json'
    );

    my $metayml = join("\n\t", @write_metayml);
    my $metajson = join("\n\t", @write_metajson);
    return sprintf <<'MAKE_FRAG', $metayml, $metajson;
metafile : create_distdir
	$(NOECHO) $(ECHO) Generating META.yml
	%s
	-$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml
	$(NOECHO) $(ECHO) Generating META.json
	%s
	-$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json
MAKE_FRAG

}

=begin private

=head3 _fix_metadata_before_conversion

    $mm->_fix_metadata_before_conversion( \%metadata );

Fixes errors in the metadata before it's handed off to L<CPAN::Meta> for
conversion. This hopefully results in something that can be used further
on, no guarantee is made though.

=end private

=cut

sub _fix_metadata_before_conversion {
    my ( $self, $metadata ) = @_;

    # we should never be called unless this already passed but
    # prefer to be defensive in case somebody else calls this

    return unless _has_cpan_meta;

    my $bad_version = $metadata->{version} &&
                      !CPAN::Meta::Validator->new->version( 'version', $metadata->{version} );
    # just delete all invalid versions
    if( $bad_version ) {
        warn "Can't parse version '$metadata->{version}'\n";
        $metadata->{version} = '';
    }

    my $validator2 = CPAN::Meta::Validator->new( $metadata );
    my @errors;
    push @errors, $validator2->errors if !$validator2->is_valid;
    my $validator14 = CPAN::Meta::Validator->new(
        {
            %$metadata,
            'meta-spec' => { version => 1.4 },
        }
    );
    push @errors, $validator14->errors if !$validator14->is_valid;
    # fix non-camelcase custom resource keys (only other trick we know)
    for my $error ( @errors ) {
        my ( $key ) = ( $error =~ /Custom resource '(.*)' must be in CamelCase./ );
        next if !$key;

        # first try to remove all non-alphabetic chars
        ( my $new_key = $key ) =~ s/[^_a-zA-Z]//g;

        # if that doesn't work, uppercase first one
        $new_key = ucfirst $new_key if !$validator14->custom_1( $new_key );

        # copy to new key if that worked
        $metadata->{resources}{$new_key} = $metadata->{resources}{$key}
          if $validator14->custom_1( $new_key );

        # and delete old one in any case
        delete $metadata->{resources}{$key};
    }

    # paper over validation issues, but still complain, necessary because
    # there's no guarantee that the above will fix ALL errors
    my $meta = eval { CPAN::Meta->create( $metadata, { lazy_validation => 1 } ) };
    warn $@ if $@ and
               $@ !~ /encountered CODE.*, but JSON can only represent references to arrays or hashes/;

    # use the original metadata straight if the conversion failed
    # or if it can't be stringified.
    if( !$meta                                                  ||
        !eval { $meta->as_string( { version => $METASPEC_V } ) }      ||
        !eval { $meta->as_string }
    ) {
        $meta = bless $metadata, 'CPAN::Meta';
    }

    my $now_license = $meta->as_struct({ version => 2 })->{license};
    if ($self->{LICENSE} and $self->{LICENSE} ne 'unknown' and
        @{$now_license} == 1 and $now_license->[0] eq 'unknown'
    ) {
        warn "Invalid LICENSE value '$self->{LICENSE}' ignored\n";
    }

    $meta;
}


=begin private

=head3 _sort_pairs

    my @pairs = _sort_pairs($sort_sub, \%hash);

Sorts the pairs of a hash based on keys ordered according
to C<$sort_sub>.

=end private

=cut

sub _sort_pairs {
    my $sort  = shift;
    my $pairs = shift;
    return map  { $_ => $pairs->{$_} }
           sort $sort
           keys %$pairs;
}


# Taken from Module::Build::Base
sub _hash_merge {
    my ($self, $h, $k, $v) = @_;
    if (ref $h->{$k} eq 'ARRAY') {
        push @{$h->{$k}}, ref $v ? @$v : $v;
    } elsif (ref $h->{$k} eq 'HASH') {
        $self->_hash_merge($h->{$k}, $_, $v->{$_}) foreach keys %$v;
    } else {
        $h->{$k} = $v;
    }
}


=head3 metafile_data

    my $metadata_hashref = $mm->metafile_data(\%meta_add, \%meta_merge);

Returns the data which MakeMaker turns into the META.yml file 
and the META.json file. It is always in version 2.0 of the format.

Values of %meta_add will overwrite any existing metadata in those
keys.  %meta_merge will be merged with them.

=cut

sub metafile_data {
    my $self = shift;
    my($meta_add, $meta_merge) = @_;

    $meta_add ||= {};
    $meta_merge ||= {};

    my $version = _normalize_version($self->{VERSION});
    my $release_status = ($version =~ /_/) ? 'unstable' : 'stable';
    my %meta = (
        # required
        abstract     => $self->{ABSTRACT} || 'unknown',
        author       => defined($self->{AUTHOR}) ? $self->{AUTHOR} : ['unknown'],
        dynamic_config => 1,
        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
        license      => [ $self->{LICENSE} || 'unknown' ],
        'meta-spec'  => {
            url         => $METASPEC_URL,
            version     => $METASPEC_V,
        },
        name         => $self->{DISTNAME},
        release_status => $release_status,
        version      => $version,

        # optional
        no_index     => { directory => [qw(t inc)] },
    );
    $self->_add_requirements_to_meta(\%meta);

    if (!eval { require JSON::PP; require CPAN::Meta::Converter; CPAN::Meta::Converter->VERSION(2.141170) }) {
      return \%meta;
    }

    # needs to be based on the original version
    my $v1_add = _metaspec_version($meta_add) !~ /^2/;

    my ($add_v, $merge_v) = map _metaspec_version($_), $meta_add, $meta_merge;
    for my $frag ($meta_add, $meta_merge) {
        my $def_v = $frag == $meta_add ? $merge_v : $add_v;
        $frag = CPAN::Meta::Converter->new($frag, default_version => $def_v)->upgrade_fragment;
    }

    # if we upgraded a 1.x _ADD fragment, we gave it a prereqs key that
    # will override all prereqs, which is more than the user asked for;
    # instead, we'll go inside the prereqs and override all those
    while( my($key, $val) = each %$meta_add ) {
        if ($v1_add and $key eq 'prereqs') {
            $meta{$key}{$_} = $val->{$_} for keys %$val;
        } elsif ($key ne 'meta-spec') {
            $meta{$key} = $val;
        }
    }

    while( my($key, $val) = each %$meta_merge ) {
        next if $key eq 'meta-spec';
        $self->_hash_merge(\%meta, $key, $val);
    }

    return \%meta;
}


=begin private

=cut

sub _add_requirements_to_meta {
    my ( $self, $meta ) = @_;
    # Check the original args so we can tell between the user setting it
    # to an empty hash and it just being initialized.
    $meta->{prereqs}{configure}{requires} = $self->{ARGS}{CONFIGURE_REQUIRES}
        ? $self->{CONFIGURE_REQUIRES}
        : { 'ExtUtils::MakeMaker' => 0, };
    $meta->{prereqs}{build}{requires} = $self->{ARGS}{BUILD_REQUIRES}
        ? $self->{BUILD_REQUIRES}
        : { 'ExtUtils::MakeMaker' => 0, };
    $meta->{prereqs}{test}{requires} = $self->{TEST_REQUIRES}
        if $self->{ARGS}{TEST_REQUIRES};
    $meta->{prereqs}{runtime}{requires} = $self->{PREREQ_PM}
        if $self->{ARGS}{PREREQ_PM};
    $meta->{prereqs}{runtime}{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
        if $self->{MIN_PERL_VERSION};
}

# spec version of given fragment - if not given, assume 1.4
sub _metaspec_version {
  my ( $meta ) = @_;
  return $meta->{'meta-spec'}->{version}
    if defined $meta->{'meta-spec'}
       and defined $meta->{'meta-spec'}->{version};
  return '1.4';
}

sub _add_requirements_to_meta_v1_4 {
    my ( $self, $meta ) = @_;
    # Check the original args so we can tell between the user setting it
    # to an empty hash and it just being initialized.
    if( $self->{ARGS}{CONFIGURE_REQUIRES} ) {
        $meta->{configure_requires} = $self->{CONFIGURE_REQUIRES};
    } else {
        $meta->{configure_requires} = {
            'ExtUtils::MakeMaker'       => 0,
        };
    }
    if( $self->{ARGS}{BUILD_REQUIRES} ) {
        $meta->{build_requires} = $self->{BUILD_REQUIRES};
    } else {
        $meta->{build_requires} = {
            'ExtUtils::MakeMaker'       => 0,
        };
    }
    if( $self->{ARGS}{TEST_REQUIRES} ) {
        $meta->{build_requires} = {
          %{ $meta->{build_requires} },
          %{ $self->{TEST_REQUIRES} },
        };
    }
    $meta->{requires} = $self->{PREREQ_PM}
        if defined $self->{PREREQ_PM};
    $meta->{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
        if $self->{MIN_PERL_VERSION};
}

# Adapted from Module::Build::Base
sub _normalize_version {
  my ($version) = @_;
  $version = 0 unless defined $version;

  if ( ref $version eq 'version' ) { # version objects
    $version = $version->stringify;
  }
  elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
    # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
    $version = "v$version";
  }
  else {
    # leave alone
  }
  return $version;
}

=head3 _dump_hash

    $yaml = _dump_hash(\%options, %hash);

Implements a fake YAML dumper for a hash given
as a list of pairs. No quoting/escaping is done. Keys
are supposed to be strings. Values are undef, strings,
hash refs or array refs of strings.

Supported options are:

    delta => STR - indentation delta
    use_header => BOOL - whether to include a YAML header
    indent => STR - a string of spaces
          default: ''

    max_key_length => INT - maximum key length used to align
        keys and values of the same hash
        default: 20
    key_sort => CODE - a sort sub
            It may be undef, which means no sorting by keys
        default: sub { lc $a cmp lc $b }

    customs => HASH - special options for certain keys
           (whose values are hashes themselves)
        may contain: max_key_length, key_sort, customs

=end private

=cut

sub _dump_hash {
    croak "first argument should be a hash ref" unless ref $_[0] eq 'HASH';
    my $options = shift;
    my %hash = @_;

    # Use a list to preserve order.
    my @pairs;

    my $k_sort
        = exists $options->{key_sort} ? $options->{key_sort}
                                      : sub { lc $a cmp lc $b };
    if ($k_sort) {
        croak "'key_sort' should be a coderef" unless ref $k_sort eq 'CODE';
        @pairs = _sort_pairs($k_sort, \%hash);
    } else { # list of pairs, no sorting
        @pairs = @_;
    }

    my $yaml     = $options->{use_header} ? "--- #YAML:1.0\n" : '';
    my $indent   = $options->{indent} || '';
    my $k_length = min(
        ($options->{max_key_length} || 20),
        max(map { length($_) + 1 } grep { !ref $hash{$_} } keys %hash)
    );
    my $customs  = $options->{customs} || {};

    # printf format for key
    my $k_format = "%-${k_length}s";

    while( @pairs ) {
        my($key, $val) = splice @pairs, 0, 2;
        $val = '~' unless defined $val;
        if(ref $val eq 'HASH') {
            if ( keys %$val ) {
                my %k_options = ( # options for recursive call
                    delta => $options->{delta},
                    use_header => 0,
                    indent => $indent . $options->{delta},
                );
                if (exists $customs->{$key}) {
                    my %k_custom = %{$customs->{$key}};
                    foreach my $k (qw(key_sort max_key_length customs)) {
                        $k_options{$k} = $k_custom{$k} if exists $k_custom{$k};
                    }
                }
                $yaml .= $indent . "$key:\n"
                  . _dump_hash(\%k_options, %$val);
            }
            else {
                $yaml .= $indent . "$key:  {}\n";
            }
        }
        elsif (ref $val eq 'ARRAY') {
            if( @$val ) {
                $yaml .= $indent . "$key:\n";

                for (@$val) {
                    croak "only nested arrays of non-refs are supported" if ref $_;
                    $yaml .= $indent . $options->{delta} . "- $_\n";
                }
            }
            else {
                $yaml .= $indent . "$key:  []\n";
            }
        }
        elsif( ref $val and !blessed($val) ) {
            croak "only nested hashes, arrays and objects are supported";
        }
        else {  # if it's an object, just stringify it
            $yaml .= $indent . sprintf "$k_format  %s\n", "$key:", $val;
        }
    };

    return $yaml;

}

sub blessed {
    return eval { $_[0]->isa("UNIVERSAL"); };
}

sub max {
    return (sort { $b <=> $a } @_)[0];
}

sub min {
    return (sort { $a <=> $b } @_)[0];
}

=head3 metafile_file

    my $meta_yml = $mm->metafile_file(@metadata_pairs);

Turns the @metadata_pairs into YAML.

This method does not implement a complete YAML dumper, being limited
to dump a hash with values which are strings, undef's or nested hashes
and arrays of strings. No quoting/escaping is done.

=cut

sub metafile_file {
    my $self = shift;

    my %dump_options = (
        use_header => 1,
        delta      => ' ' x 4,
        key_sort   => undef,
    );
    return _dump_hash(\%dump_options, @_);

}


=head3 distmeta_target

    my $make_frag = $mm->distmeta_target;

Generates the distmeta target to add META.yml and META.json to the MANIFEST
in the distdir.

=cut

sub distmeta_target {
    my $self = shift;

    my @add_meta = (
      $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']),
exit unless -e q{META.yml};
eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }
    or die "Could not add META.yml to MANIFEST: ${'@'}"
CODE
      $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd'])
exit unless -f q{META.json};
eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }
    or die "Could not add META.json to MANIFEST: ${'@'}"
CODE
    );

    my @add_meta_to_distdir = map { $self->cd('$(DISTVNAME)', $_) } @add_meta;

    return sprintf <<'MAKE', @add_meta_to_distdir;
distmeta : create_distdir metafile
	$(NOECHO) %s
	$(NOECHO) %s

MAKE

}


=head3 mymeta

    my $mymeta = $mm->mymeta;

Generate MYMETA information as a hash either from an existing CPAN Meta file
(META.json or META.yml) or from internal data.

=cut

sub mymeta {
    my $self = shift;
    my $file = shift || ''; # for testing

    my $mymeta = $self->_mymeta_from_meta($file);
    my $v2 = 1;

    unless ( $mymeta ) {
        $mymeta = $self->metafile_data(
            $self->{META_ADD}   || {},
            $self->{META_MERGE} || {},
        );
        $v2 = 0;
    }

    # Overwrite the non-configure dependency hashes
    $self->_add_requirements_to_meta($mymeta);

    $mymeta->{dynamic_config} = 0;

    return $mymeta;
}


sub _mymeta_from_meta {
    my $self = shift;
    my $metafile = shift || ''; # for testing

    return unless _has_cpan_meta();

    my $meta;
    for my $file ( $metafile, "META.json", "META.yml" ) {
      next unless -e $file;
      eval {
          $meta = CPAN::Meta->load_file($file)->as_struct( { version => 2 } );
      };
      last if $meta;
    }
    return unless $meta;

    # META.yml before 6.25_01 cannot be trusted.  META.yml lived in the source directory.
    # There was a good chance the author accidentally uploaded a stale META.yml if they
    # rolled their own tarball rather than using "make dist".
    if ($meta->{generated_by} &&
        $meta->{generated_by} =~ /ExtUtils::MakeMaker version ([\d\._]+)/) {
        my $eummv = do { no warnings; $1+0; };
        if ($eummv < 6.2501) {
            return;
        }
    }

    return $meta;
}

=head3 write_mymeta

    $self->write_mymeta( $mymeta );

Write MYMETA information to MYMETA.json and MYMETA.yml.

=cut

sub write_mymeta {
    my $self = shift;
    my $mymeta = shift;

    return unless _has_cpan_meta();

    my $meta_obj = $self->_fix_metadata_before_conversion( $mymeta );

    $meta_obj->save( 'MYMETA.json', { version => "2.0" } );
    $meta_obj->save( 'MYMETA.yml', { version => "1.4" } );
    return 1;
}

=head3 realclean (o)

Defines the realclean target.

=cut

sub realclean {
    my($self, %attribs) = @_;

    my @dirs  = qw($(DISTVNAME));
    my @files = qw($(FIRST_MAKEFILE) $(MAKEFILE_OLD));

    # Special exception for the perl core where INST_* is not in blib.
    # This cleans up the files built from the ext/ directory (all XS).
    if( $self->{PERL_CORE} ) {
        push @dirs, qw($(INST_AUTODIR) $(INST_ARCHAUTODIR));
        push @files, values %{$self->{PM}};
    }

    if( $self->has_link_code ){
        push @files, qw($(OBJECT));
    }

    if( $attribs{FILES} ) {
        if( ref $attribs{FILES} ) {
            push @dirs, @{ $attribs{FILES} };
        }
        else {
            push @dirs, split /\s+/, $attribs{FILES};
        }
    }

    # Occasionally files are repeated several times from different sources
    { my(%f) = map { ($_ => 1) } @files;  @files = sort keys %f; }
    { my(%d) = map { ($_ => 1) } @dirs;   @dirs  = sort keys %d; }

    my $rm_cmd  = join "\n\t", map { "$_" }
                    $self->split_command('- $(RM_F)',  @files);
    my $rmf_cmd = join "\n\t", map { "$_" }
                    $self->split_command('- $(RM_RF)', @dirs);

    my $m = sprintf <<'MAKE', $rm_cmd, $rmf_cmd;
# Delete temporary files (via clean) and also delete dist files
realclean purge :: realclean_subdirs
	%s
	%s
MAKE

    $m .= "\t$attribs{POSTOP}\n" if $attribs{POSTOP};

    return $m;
}


=head3 realclean_subdirs_target

  my $make_frag = $MM->realclean_subdirs_target;

Returns the realclean_subdirs target.  This is used by the realclean
target to call realclean on any subdirectories which contain Makefiles.

=cut

sub realclean_subdirs_target {
    my $self = shift;
    my @m = <<'EOF';
# so clean is forced to complete before realclean_subdirs runs
realclean_subdirs : clean
EOF
    return join '', @m, "\t\$(NOECHO) \$(NOOP)\n" unless @{$self->{DIR}};
    foreach my $dir (@{$self->{DIR}}) {
        foreach my $makefile ('$(MAKEFILE_OLD)', '$(FIRST_MAKEFILE)' ) {
            my $subrclean .= $self->oneliner(_sprintf562 <<'CODE', $dir, $makefile);
chdir '%1$s';  system '$(MAKE) $(USEMAKEFILE) %2$s realclean' if -f '%2$s';
CODE
            push @m, "\t- $subrclean\n";
        }
    }
    return join '', @m;
}


=head3 signature_target

    my $target = $mm->signature_target;

Generate the signature target.

Writes the file SIGNATURE with "cpansign -s".

=cut

sub signature_target {
    my $self = shift;

    return <<'MAKE_FRAG';
signature :
	cpansign -s
MAKE_FRAG

}


=head3 distsignature_target

    my $make_frag = $mm->distsignature_target;

Generates the distsignature target to add SIGNATURE to the MANIFEST in the
distdir.

=cut

sub distsignature_target {
    my $self = shift;

    my $add_sign = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']);
eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) }
    or die "Could not add SIGNATURE to MANIFEST: ${'@'}"
CODE

    my $sign_dist        = $self->cd('$(DISTVNAME)' => 'cpansign -s');

    # cpansign -s complains if SIGNATURE is in the MANIFEST yet does not
    # exist
    my $touch_sig        = $self->cd('$(DISTVNAME)' => '$(TOUCH) SIGNATURE');
    my $add_sign_to_dist = $self->cd('$(DISTVNAME)' => $add_sign );

    return sprintf <<'MAKE', $add_sign_to_dist, $touch_sig, $sign_dist
distsignature : distmeta
	$(NOECHO) %s
	$(NOECHO) %s
	%s

MAKE

}


=head3 special_targets

  my $make_frag = $mm->special_targets

Returns a make fragment containing any targets which have special
meaning to make.  For example, .SUFFIXES and .PHONY.

=cut

sub special_targets {
    my $make_frag = <<'MAKE_FRAG';
.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)

.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir pure_all subdirs clean_subdirs makemakerdflt manifypods realclean_subdirs subdirs_dynamic subdirs_pure_nolink subdirs_static subdirs-test_dynamic subdirs-test_static test_dynamic test_static

MAKE_FRAG

    $make_frag .= <<'MAKE_FRAG' if $ENV{CLEARCASE_ROOT};
.NO_CONFIG_REC: Makefile

MAKE_FRAG

    return $make_frag;
}




=head2 Init methods

Methods which help initialize the MakeMaker object and macros.


=head3 init_ABSTRACT

    $mm->init_ABSTRACT

=cut

sub init_ABSTRACT {
    my $self = shift;

    if( $self->{ABSTRACT_FROM} and $self->{ABSTRACT} ) {
        warn "Both ABSTRACT_FROM and ABSTRACT are set.  ".
             "Ignoring ABSTRACT_FROM.\n";
        return;
    }

    if ($self->{ABSTRACT_FROM}){
        $self->{ABSTRACT} = $self->parse_abstract($self->{ABSTRACT_FROM}) or
            carp "WARNING: Setting ABSTRACT via file ".
                 "'$self->{ABSTRACT_FROM}' failed\n";
    }

    if ($self->{ABSTRACT} && $self->{ABSTRACT} =~ m![[:cntrl:]]+!) {
            warn "WARNING: ABSTRACT contains control character(s),".
                 " they will be removed\n";
            $self->{ABSTRACT} =~ s![[:cntrl:]]+!!g;
            return;
    }
}

=head3 init_INST

    $mm->init_INST;

Called by init_main.  Sets up all INST_* variables except those related
to XS code.  Those are handled in init_xs.

=cut

sub init_INST {
    my($self) = shift;

    $self->{INST_ARCHLIB} ||= $self->catdir($Curdir,"blib","arch");
    $self->{INST_BIN}     ||= $self->catdir($Curdir,'blib','bin');

    # INST_LIB typically pre-set if building an extension after
    # perl has been built and installed. Setting INST_LIB allows
    # you to build directly into, say $Config{privlibexp}.
    unless ($self->{INST_LIB}){
        if ($self->{PERL_CORE}) {
            $self->{INST_LIB} = $self->{INST_ARCHLIB} = $self->{PERL_LIB};
        } else {
            $self->{INST_LIB} = $self->catdir($Curdir,"blib","lib");
        }
    }

    my @parentdir = split(/::/, $self->{PARENT_NAME});
    $self->{INST_LIBDIR}      = $self->catdir('$(INST_LIB)',     @parentdir);
    $self->{INST_ARCHLIBDIR}  = $self->catdir('$(INST_ARCHLIB)', @parentdir);
    $self->{INST_AUTODIR}     = $self->catdir('$(INST_LIB)', 'auto',
                                              '$(FULLEXT)');
    $self->{INST_ARCHAUTODIR} = $self->catdir('$(INST_ARCHLIB)', 'auto',
                                              '$(FULLEXT)');

    $self->{INST_SCRIPT}  ||= $self->catdir($Curdir,'blib','script');

    $self->{INST_MAN1DIR} ||= $self->catdir($Curdir,'blib','man1');
    $self->{INST_MAN3DIR} ||= $self->catdir($Curdir,'blib','man3');

    return 1;
}


=head3 init_INSTALL

    $mm->init_INSTALL;

Called by init_main.  Sets up all INSTALL_* variables (except
INSTALLDIRS) and *PREFIX.

=cut

sub init_INSTALL {
    my($self) = shift;

    if( $self->{ARGS}{INSTALL_BASE} and $self->{ARGS}{PREFIX} ) {
        die "Only one of PREFIX or INSTALL_BASE can be given.  Not both.\n";
    }

    if( $self->{ARGS}{INSTALL_BASE} ) {
        $self->init_INSTALL_from_INSTALL_BASE;
    }
    else {
        $self->init_INSTALL_from_PREFIX;
    }
}


=head3 init_INSTALL_from_PREFIX

  $mm->init_INSTALL_from_PREFIX;

=cut

sub init_INSTALL_from_PREFIX {
    my $self = shift;

    $self->init_lib2arch;

    # There are often no Config.pm defaults for these new man variables so
    # we fall back to the old behavior which is to use installman*dir
    foreach my $num (1, 3) {
        my $k = 'installsiteman'.$num.'dir';

        $self->{uc $k} ||= uc "\$(installman${num}dir)"
          unless $Config{$k};
    }

    foreach my $num (1, 3) {
        my $k = 'installvendorman'.$num.'dir';

        unless( $Config{$k} ) {
            $self->{uc $k}  ||= $Config{usevendorprefix}
                              ? uc "\$(installman${num}dir)"
                              : '';
        }
    }

    $self->{INSTALLSITEBIN} ||= '$(INSTALLBIN)'
      unless $Config{installsitebin};
    $self->{INSTALLSITESCRIPT} ||= '$(INSTALLSCRIPT)'
      unless $Config{installsitescript};

    unless( $Config{installvendorbin} ) {
        $self->{INSTALLVENDORBIN} ||= $Config{usevendorprefix}
                                    ? $Config{installbin}
                                    : '';
    }
    unless( $Config{installvendorscript} ) {
        $self->{INSTALLVENDORSCRIPT} ||= $Config{usevendorprefix}
                                       ? $Config{installscript}
                                       : '';
    }


    my $iprefix = $Config{installprefixexp} || $Config{installprefix} ||
                  $Config{prefixexp}        || $Config{prefix} || '';
    my $vprefix = $Config{usevendorprefix}  ? $Config{vendorprefixexp} : '';
    my $sprefix = $Config{siteprefixexp}    || '';

    # 5.005_03 doesn't have a siteprefix.
    $sprefix = $iprefix unless $sprefix;


    $self->{PREFIX}       ||= '';

    if( $self->{PREFIX} ) {
        @{$self}{qw(PERLPREFIX SITEPREFIX VENDORPREFIX)} =
          ('$(PREFIX)') x 3;
    }
    else {
        $self->{PERLPREFIX}   ||= $iprefix;
        $self->{SITEPREFIX}   ||= $sprefix;
        $self->{VENDORPREFIX} ||= $vprefix;

        # Lots of MM extension authors like to use $(PREFIX) so we
        # put something sensible in there no matter what.
        $self->{PREFIX} = '$('.uc $self->{INSTALLDIRS}.'PREFIX)';
    }

    my $arch    = $Config{archname};
    my $version = $Config{version};

    # default style
    my $libstyle = $Config{installstyle} || 'lib/perl5';
    my $manstyle = '';

    if( $self->{LIBSTYLE} ) {
        $libstyle = $self->{LIBSTYLE};
        $manstyle = $self->{LIBSTYLE} eq 'lib/perl5' ? 'lib/perl5' : '';
    }

    # Some systems, like VOS, set installman*dir to '' if they can't
    # read man pages.
    for my $num (1, 3) {
        $self->{'INSTALLMAN'.$num.'DIR'} ||= 'none'
          unless $Config{'installman'.$num.'dir'};
    }

    my %bin_layouts =
    (
        bin         => { s => $iprefix,
                         t => 'perl',
                         d => 'bin' },
        vendorbin   => { s => $vprefix,
                         t => 'vendor',
                         d => 'bin' },
        sitebin     => { s => $sprefix,
                         t => 'site',
                         d => 'bin' },
        script      => { s => $iprefix,
                         t => 'perl',
                         d => 'bin' },
        vendorscript=> { s => $vprefix,
                         t => 'vendor',
                         d => 'bin' },
        sitescript  => { s => $sprefix,
                         t => 'site',
                         d => 'bin' },
    );

    my %man_layouts =
    (
        man1dir         => { s => $iprefix,
                             t => 'perl',
                             d => 'man/man1',
                             style => $manstyle, },
        siteman1dir     => { s => $sprefix,
                             t => 'site',
                             d => 'man/man1',
                             style => $manstyle, },
        vendorman1dir   => { s => $vprefix,
                             t => 'vendor',
                             d => 'man/man1',
                             style => $manstyle, },

        man3dir         => { s => $iprefix,
                             t => 'perl',
                             d => 'man/man3',
                             style => $manstyle, },
        siteman3dir     => { s => $sprefix,
                             t => 'site',
                             d => 'man/man3',
                             style => $manstyle, },
        vendorman3dir   => { s => $vprefix,
                             t => 'vendor',
                             d => 'man/man3',
                             style => $manstyle, },
    );

    my %lib_layouts =
    (
        privlib     => { s => $iprefix,
                         t => 'perl',
                         d => '',
                         style => $libstyle, },
        vendorlib   => { s => $vprefix,
                         t => 'vendor',
                         d => '',
                         style => $libstyle, },
        sitelib     => { s => $sprefix,
                         t => 'site',
                         d => 'site_perl',
                         style => $libstyle, },

        archlib     => { s => $iprefix,
                         t => 'perl',
                         d => "$version/$arch",
                         style => $libstyle },
        vendorarch  => { s => $vprefix,
                         t => 'vendor',
                         d => "$version/$arch",
                         style => $libstyle },
        sitearch    => { s => $sprefix,
                         t => 'site',
                         d => "site_perl/$version/$arch",
                         style => $libstyle },
    );


    # Special case for LIB.
    if( $self->{LIB} ) {
        foreach my $var (keys %lib_layouts) {
            my $Installvar = uc "install$var";

            if( $var =~ /arch/ ) {
                $self->{$Installvar} ||=
                  $self->catdir($self->{LIB}, $Config{archname});
            }
            else {
                $self->{$Installvar} ||= $self->{LIB};
            }
        }
    }

    my %type2prefix = ( perl    => 'PERLPREFIX',
                        site    => 'SITEPREFIX',
                        vendor  => 'VENDORPREFIX'
                      );

    my %layouts = (%bin_layouts, %man_layouts, %lib_layouts);
    while( my($var, $layout) = each(%layouts) ) {
        my($s, $t, $d, $style) = @{$layout}{qw(s t d style)};
        my $r = '$('.$type2prefix{$t}.')';

        warn "Prefixing $var\n" if $Verbose >= 2;

        my $installvar = "install$var";
        my $Installvar = uc $installvar;
        next if $self->{$Installvar};

        $d = "$style/$d" if $style;
        $self->prefixify($installvar, $s, $r, $d);

        warn "  $Installvar == $self->{$Installvar}\n"
          if $Verbose >= 2;
    }

    # Generate these if they weren't figured out.
    $self->{VENDORARCHEXP} ||= $self->{INSTALLVENDORARCH};
    $self->{VENDORLIBEXP}  ||= $self->{INSTALLVENDORLIB};

    return 1;
}


=head3 init_from_INSTALL_BASE

    $mm->init_from_INSTALL_BASE

=cut

my %map = (
           lib      => [qw(lib perl5)],
           arch     => [('lib', 'perl5', $Config{archname})],
           bin      => [qw(bin)],
           man1dir  => [qw(man man1)],
           man3dir  => [qw(man man3)]
          );
$map{script} = $map{bin};

sub init_INSTALL_from_INSTALL_BASE {
    my $self = shift;

    @{$self}{qw(PREFIX VENDORPREFIX SITEPREFIX PERLPREFIX)} =
                                                         '$(INSTALL_BASE)';

    my %install;
    foreach my $thing (keys %map) {
        foreach my $dir (('', 'SITE', 'VENDOR')) {
            my $uc_thing = uc $thing;
            my $key = "INSTALL".$dir.$uc_thing;

            $install{$key} ||=
                ($thing =~ /^man.dir$/ and not $Config{lc $key})
                ? 'none'
                : $self->catdir('$(INSTALL_BASE)', @{$map{$thing}});
        }
    }

    # Adjust for variable quirks.
    $install{INSTALLARCHLIB} ||= delete $install{INSTALLARCH};
    $install{INSTALLPRIVLIB} ||= delete $install{INSTALLLIB};

    foreach my $key (keys %install) {
        $self->{$key} ||= $install{$key};
    }

    return 1;
}


=head3 init_VERSION  I<Abstract>

    $mm->init_VERSION

Initialize macros representing versions of MakeMaker and other tools

MAKEMAKER: path to the MakeMaker module.

MM_VERSION: ExtUtils::MakeMaker Version

MM_REVISION: ExtUtils::MakeMaker version control revision (for backwards
             compat)

VERSION: version of your module

VERSION_MACRO: which macro represents the version (usually 'VERSION')

VERSION_SYM: like version but safe for use as an RCS revision number

DEFINE_VERSION: -D line to set the module version when compiling

XS_VERSION: version in your .xs file.  Defaults to $(VERSION)

XS_VERSION_MACRO: which macro represents the XS version.

XS_DEFINE_VERSION: -D line to set the xs version when compiling.

Called by init_main.

=cut

sub init_VERSION {
    my($self) = shift;

    $self->{MAKEMAKER}  = $ExtUtils::MakeMaker::Filename;
    $self->{MM_VERSION} = $ExtUtils::MakeMaker::VERSION;
    $self->{MM_REVISION}= $ExtUtils::MakeMaker::Revision;
    $self->{VERSION_FROM} ||= '';

    if ($self->{VERSION_FROM}){
        $self->{VERSION} = $self->parse_version($self->{VERSION_FROM});
        if( $self->{VERSION} eq 'undef' ) {
            carp("WARNING: Setting VERSION via file ".
                 "'$self->{VERSION_FROM}' failed\n");
        }
    }

    if (defined $self->{VERSION}) {
        if ( $self->{VERSION} !~ /^\s*v?[\d_\.]+\s*$/ ) {
          require version;
          my $normal = eval { version->new( $self->{VERSION} ) };
          $self->{VERSION} = $normal if defined $normal;
        }
        $self->{VERSION} =~ s/^\s+//;
        $self->{VERSION} =~ s/\s+$//;
    }
    else {
        $self->{VERSION} = '';
    }


    $self->{VERSION_MACRO}  = 'VERSION';
    ($self->{VERSION_SYM} = $self->{VERSION}) =~ s/\W/_/g;
    $self->{DEFINE_VERSION} = '-D$(VERSION_MACRO)=\"$(VERSION)\"';


    # Graham Barr and Paul Marquess had some ideas how to ensure
    # version compatibility between the *.pm file and the
    # corresponding *.xs file. The bottom line was, that we need an
    # XS_VERSION macro that defaults to VERSION:
    $self->{XS_VERSION} ||= $self->{VERSION};

    $self->{XS_VERSION_MACRO}  = 'XS_VERSION';
    $self->{XS_DEFINE_VERSION} = '-D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"';

}


=head3 init_tools

    $MM->init_tools();

Initializes the simple macro definitions used by tools_other() and
places them in the $MM object.  These use conservative cross platform
versions and should be overridden with platform specific versions for
performance.

Defines at least these macros.

  Macro             Description

  NOOP              Do nothing
  NOECHO            Tell make not to display the command itself

  SHELL             Program used to run shell commands

  ECHO              Print text adding a newline on the end
  RM_F              Remove a file
  RM_RF             Remove a directory
  TOUCH             Update a file's timestamp
  TEST_F            Test for a file's existence
  TEST_S            Test the size of a file
  CP                Copy a file
  CP_NONEMPTY       Copy a file if it is not empty
  MV                Move a file
  CHMOD             Change permissions on a file
  FALSE             Exit with non-zero
  TRUE              Exit with zero

  UMASK_NULL        Nullify umask
  DEV_NULL          Suppress all command output

=cut

sub init_tools {
    my $self = shift;

    $self->{ECHO}     ||= $self->oneliner('binmode STDOUT, qq{:raw}; print qq{@ARGV}', ['-l']);
    $self->{ECHO_N}   ||= $self->oneliner('print qq{@ARGV}');

    $self->{TOUCH}    ||= $self->oneliner('touch', ["-MExtUtils::Command"]);
    $self->{CHMOD}    ||= $self->oneliner('chmod', ["-MExtUtils::Command"]);
    $self->{RM_F}     ||= $self->oneliner('rm_f',  ["-MExtUtils::Command"]);
    $self->{RM_RF}    ||= $self->oneliner('rm_rf', ["-MExtUtils::Command"]);
    $self->{TEST_F}   ||= $self->oneliner('test_f', ["-MExtUtils::Command"]);
    $self->{TEST_S}   ||= $self->oneliner('test_s', ["-MExtUtils::Command::MM"]);
    $self->{CP_NONEMPTY} ||= $self->oneliner('cp_nonempty', ["-MExtUtils::Command::MM"]);
    $self->{FALSE}    ||= $self->oneliner('exit 1');
    $self->{TRUE}     ||= $self->oneliner('exit 0');

    $self->{MKPATH}   ||= $self->oneliner('mkpath', ["-MExtUtils::Command"]);

    $self->{CP}       ||= $self->oneliner('cp', ["-MExtUtils::Command"]);
    $self->{MV}       ||= $self->oneliner('mv', ["-MExtUtils::Command"]);

    $self->{MOD_INSTALL} ||=
      $self->oneliner(<<'CODE', ['-MExtUtils::Install']);
install([ from_to => {@ARGV}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]);
CODE
    $self->{DOC_INSTALL} ||= $self->oneliner('perllocal_install', ["-MExtUtils::Command::MM"]);
    $self->{UNINSTALL}   ||= $self->oneliner('uninstall', ["-MExtUtils::Command::MM"]);
    $self->{WARN_IF_OLD_PACKLIST} ||=
      $self->oneliner('warn_if_old_packlist', ["-MExtUtils::Command::MM"]);
    $self->{FIXIN}       ||= $self->oneliner('MY->fixin(shift)', ["-MExtUtils::MY"]);
    $self->{EQUALIZE_TIMESTAMP} ||= $self->oneliner('eqtime', ["-MExtUtils::Command"]);

    $self->{UNINST}     ||= 0;
    $self->{VERBINST}   ||= 0;

    $self->{SHELL}              ||= $Config{sh};

    # UMASK_NULL is not used by MakeMaker but some CPAN modules
    # make use of it.
    $self->{UMASK_NULL}         ||= "umask 0";

    # Not the greatest default, but its something.
    $self->{DEV_NULL}           ||= "> /dev/null 2>&1";

    $self->{NOOP}               ||= '$(TRUE)';
    $self->{NOECHO}             = '@' unless defined $self->{NOECHO};

    $self->{FIRST_MAKEFILE}     ||= $self->{MAKEFILE} || 'Makefile';
    $self->{MAKEFILE}           ||= $self->{FIRST_MAKEFILE};
    $self->{MAKEFILE_OLD}       ||= $self->{MAKEFILE}.'.old';
    $self->{MAKE_APERL_FILE}    ||= $self->{MAKEFILE}.'.aperl';

    # Not everybody uses -f to indicate "use this Makefile instead"
    $self->{USEMAKEFILE}        ||= '-f';

    # Some makes require a wrapper around macros passed in on the command
    # line.
    $self->{MACROSTART}         ||= '';
    $self->{MACROEND}           ||= '';

    return;
}


=head3 init_others

    $MM->init_others();

Initializes the macro definitions having to do with compiling and
linking used by tools_other() and places them in the $MM object.

If there is no description, its the same as the parameter to
WriteMakefile() documented in L<ExtUtils::MakeMaker>.

=cut

sub init_others {
    my $self = shift;

    $self->{LD_RUN_PATH} = "";

    $self->{LIBS} = $self->_fix_libs($self->{LIBS});

    # Compute EXTRALIBS, BSLOADLIBS and LDLOADLIBS from $self->{LIBS}
    foreach my $libs ( @{$self->{LIBS}} ){
        $libs =~ s/^\s*(.*\S)\s*$/$1/; # remove leading and trailing whitespace
        my(@libs) = $self->extliblist($libs);
        if ($libs[0] or $libs[1] or $libs[2]){
            # LD_RUN_PATH now computed by ExtUtils::Liblist
            ($self->{EXTRALIBS},  $self->{BSLOADLIBS},
             $self->{LDLOADLIBS}, $self->{LD_RUN_PATH}) = @libs;
            last;
        }
    }

    if ( $self->{OBJECT} ) {
        $self->{OBJECT} = join(" ", @{$self->{OBJECT}}) if ref $self->{OBJECT};
        $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
    } elsif ( ($self->{MAGICXS} || $self->{XSMULTI}) && @{$self->{O_FILES}||[]} ) {
        $self->{OBJECT} = join(" ", @{$self->{O_FILES}});
        $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
    } else {
        # init_dirscan should have found out, if we have C files
        $self->{OBJECT} = "";
        $self->{OBJECT} = '$(BASEEXT)$(OBJ_EXT)' if @{$self->{C}||[]};
    }
    $self->{OBJECT} =~ s/\n+/ \\\n\t/g;

    $self->{BOOTDEP}  = (-f "$self->{BASEEXT}_BS") ? "$self->{BASEEXT}_BS" : "";
    $self->{PERLMAINCC} ||= '$(CC)';
    $self->{LDFROM} = '$(OBJECT)' unless $self->{LDFROM};

    # Sanity check: don't define LINKTYPE = dynamic if we're skipping
    # the 'dynamic' section of MM.  We don't have this problem with
    # 'static', since we either must use it (%Config says we can't
    # use dynamic loading) or the caller asked for it explicitly.
    if (!$self->{LINKTYPE}) {
       $self->{LINKTYPE} = $self->{SKIPHASH}{'dynamic'}
                        ? 'static'
                        : ($Config{usedl} ? 'dynamic' : 'static');
    }

    return;
}


# Lets look at $self->{LIBS} carefully: It may be an anon array, a string or
# undefined. In any case we turn it into an anon array
sub _fix_libs {
    my($self, $libs) = @_;

    return !defined $libs       ? ['']          :
           !ref $libs           ? [$libs]       :
           !defined $libs->[0]  ? ['']          :
                                  $libs         ;
}


=head3 tools_other

    my $make_frag = $MM->tools_other;

Returns a make fragment containing definitions for the macros init_others()
initializes.

=cut

sub tools_other {
    my($self) = shift;
    my @m;

    # We set PM_FILTER as late as possible so it can see all the earlier
    # on macro-order sensitive makes such as nmake.
    for my $tool (qw{ SHELL CHMOD CP MV NOOP NOECHO RM_F RM_RF TEST_F TOUCH
                      UMASK_NULL DEV_NULL MKPATH EQUALIZE_TIMESTAMP
                      FALSE TRUE
                      ECHO ECHO_N
                      UNINST VERBINST
                      MOD_INSTALL DOC_INSTALL UNINSTALL
                      WARN_IF_OLD_PACKLIST
                      MACROSTART MACROEND
                      USEMAKEFILE
                      PM_FILTER
                      FIXIN
                      CP_NONEMPTY
                    } )
    {
        next unless defined $self->{$tool};
        push @m, "$tool = $self->{$tool}\n";
    }

    return join "", @m;
}


=head3 init_DIRFILESEP  I<Abstract>

  $MM->init_DIRFILESEP;
  my $dirfilesep = $MM->{DIRFILESEP};

Initializes the DIRFILESEP macro which is the separator between the
directory and filename in a filepath.  ie. / on Unix, \ on Win32 and
nothing on VMS.

For example:

    # instead of $(INST_ARCHAUTODIR)/extralibs.ld
    $(INST_ARCHAUTODIR)$(DIRFILESEP)extralibs.ld

Something of a hack but it prevents a lot of code duplication between
MM_* variants.

Do not use this as a separator between directories.  Some operating
systems use different separators between subdirectories as between
directories and filenames (for example:  VOLUME:[dir1.dir2]file on VMS).

=head3 init_linker  I<Abstract>

    $mm->init_linker;

Initialize macros which have to do with linking.

PERL_ARCHIVE: path to libperl.a equivalent to be linked to dynamic
extensions.

PERL_ARCHIVE_AFTER: path to a library which should be put on the
linker command line I<after> the external libraries to be linked to
dynamic extensions.  This may be needed if the linker is one-pass, and
Perl includes some overrides for C RTL functions, such as malloc().

EXPORT_LIST: name of a file that is passed to linker to define symbols
to be exported.

Some OSes do not need these in which case leave it blank.


=head3 init_platform

    $mm->init_platform

Initialize any macros which are for platform specific use only.

A typical one is the version number of your OS specific module.
(ie. MM_Unix_VERSION or MM_VMS_VERSION).

=cut

sub init_platform {
    return '';
}


=head3 init_MAKE

    $mm->init_MAKE

Initialize MAKE from either a MAKE environment variable or $Config{make}.

=cut

sub init_MAKE {
    my $self = shift;

    $self->{MAKE} ||= $ENV{MAKE} || $Config{make};
}


=head2 Tools

A grab bag of methods to generate specific macros and commands.



=head3 manifypods

Defines targets and routines to translate the pods into manpages and
put them into the INST_* directories.

=cut

sub manifypods {
    my $self          = shift;

    my $POD2MAN_macro = $self->POD2MAN_macro();
    my $manifypods_target = $self->manifypods_target();

    return <<END_OF_TARGET;

$POD2MAN_macro

$manifypods_target

END_OF_TARGET

}


=head3 POD2MAN_macro

  my $pod2man_macro = $self->POD2MAN_macro

Returns a definition for the POD2MAN macro.  This is a program
which emulates the pod2man utility.  You can add more switches to the
command by simply appending them on the macro.

Typical usage:

    $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) podfile1 man_page1 ...

=cut

sub POD2MAN_macro {
    my $self = shift;

# Need the trailing '--' so perl stops gobbling arguments and - happens
# to be an alternative end of line separator on VMS so we quote it
    return <<'END_OF_DEF';
POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
POD2MAN = $(POD2MAN_EXE)
END_OF_DEF
}


=head3 test_via_harness

  my $command = $mm->test_via_harness($perl, $tests);

Returns a $command line which runs the given set of $tests with
Test::Harness and the given $perl.

Used on the t/*.t files.

=cut

sub test_via_harness {
    my($self, $perl, $tests) = @_;

    return qq{\t$perl "-MExtUtils::Command::MM" "-MTest::Harness" }.
           qq{"-e" "undef *Test::Harness::Switches; test_harness(\$(TEST_VERBOSE), '\$(INST_LIB)', '\$(INST_ARCHLIB)')" $tests\n};
}

=head3 test_via_script

  my $command = $mm->test_via_script($perl, $script);

Returns a $command line which just runs a single test without
Test::Harness.  No checks are done on the results, they're just
printed.

Used for test.pl, since they don't always follow Test::Harness
formatting.

=cut

sub test_via_script {
    my($self, $perl, $script) = @_;
    return qq{\t$perl "-I\$(INST_LIB)" "-I\$(INST_ARCHLIB)" $script\n};
}


=head3 tool_autosplit

Defines a simple perl call that runs autosplit. May be deprecated by
pm_to_blib soon.

=cut

sub tool_autosplit {
    my($self, %attribs) = @_;

    my $maxlen = $attribs{MAXLEN} ? '$$AutoSplit::Maxlen=$attribs{MAXLEN};'
                                  : '';

    my $asplit = $self->oneliner(sprintf <<'PERL_CODE', $maxlen);
use AutoSplit; %s autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)
PERL_CODE

    return sprintf <<'MAKE_FRAG', $asplit;
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
AUTOSPLITFILE = %s

MAKE_FRAG

}


=head3 arch_check

    my $arch_ok = $mm->arch_check(
        $INC{"Config.pm"},
        File::Spec->catfile($Config{archlibexp}, "Config.pm")
    );

A sanity check that what Perl thinks the architecture is and what
Config thinks the architecture is are the same.  If they're not it
will return false and show a diagnostic message.

When building Perl it will always return true, as nothing is installed
yet.

The interface is a bit odd because this is the result of a
quick refactoring.  Don't rely on it.

=cut

sub arch_check {
    my $self = shift;
    my($pconfig, $cconfig) = @_;

    return 1 if $self->{PERL_SRC};

    my($pvol, $pthinks) = $self->splitpath($pconfig);
    my($cvol, $cthinks) = $self->splitpath($cconfig);

    return 1 if $pthinks =~ /perl-base/; # https://bugs.debian.org/962138

    $pthinks = $self->canonpath($pthinks);
    $cthinks = $self->canonpath($cthinks);

    my $ret = 1;
    if ($pthinks ne $cthinks) {
        print "Have $pthinks\n";
        print "Want $cthinks\n";

        $ret = 0;

        my $arch = (grep length, $self->splitdir($pthinks))[-1];

        print <<END unless $self->{UNINSTALLED_PERL};
Your perl and your Config.pm seem to have different ideas about the
architecture they are running on.
Perl thinks: [$arch]
Config says: [$Config{archname}]
This may or may not cause problems. Please check your installation of perl
if you have problems building this extension.
END
    }

    return $ret;
}



=head2 File::Spec wrappers

ExtUtils::MM_Any is a subclass of L<File::Spec>.  The methods noted here
override File::Spec.



=head3 catfile

File::Spec <= 0.83 has a bug where the file part of catfile is not
canonicalized.  This override fixes that bug.

=cut

sub catfile {
    my $self = shift;
    return $self->canonpath($self->SUPER::catfile(@_));
}



=head2 Misc

Methods I can't really figure out where they should go yet.


=head3 find_tests

  my $test = $mm->find_tests;

Returns a string suitable for feeding to the shell to return all
tests in t/*.t.

=cut

sub find_tests {
    my($self) = shift;
    return -d 't' ? 't/*.t' : '';
}

=head3 find_tests_recursive

  my $tests = $mm->find_tests_recursive;

Returns a string suitable for feeding to the shell to return all
tests in t/ but recursively. Equivalent to

  my $tests = $mm->find_tests_recursive_in('t');

=cut

sub find_tests_recursive {
    my $self = shift;
    return $self->find_tests_recursive_in('t');
}

=head3 find_tests_recursive_in

  my $tests = $mm->find_tests_recursive_in($dir);

Returns a string suitable for feeding to the shell to return all
tests in $dir recursively.

=cut

sub find_tests_recursive_in {
    my($self, $dir) = @_;
    return '' unless -d $dir;

    require File::Find;

    my $base_depth = grep { $_ ne '' } File::Spec->splitdir( (File::Spec->splitpath($dir))[1] );
    my %depths;

    my $wanted = sub {
        return unless m!\.t$!;
        my ($volume,$directories,$file) =
            File::Spec->splitpath( $File::Find::name  );
        my $depth = grep { $_ ne '' } File::Spec->splitdir( $directories );
        $depth -= $base_depth;
        $depths{ $depth } = 1;
    };

    File::Find::find( $wanted, $dir );

    return join ' ',
        map { $dir . '/*' x $_ . '.t' }
        sort { $a <=> $b }
        keys %depths;
}

=head3 extra_clean_files

    my @files_to_clean = $MM->extra_clean_files;

Returns a list of OS specific files to be removed in the clean target in
addition to the usual set.

=cut

# An empty method here tickled a perl 5.8.1 bug and would return its object.
sub extra_clean_files {
    return;
}


=head3 installvars

    my @installvars = $mm->installvars;

A list of all the INSTALL* variables without the INSTALL prefix.  Useful
for iteration or building related variable sets.

=cut

sub installvars {
    return qw(PRIVLIB SITELIB  VENDORLIB
              ARCHLIB SITEARCH VENDORARCH
              BIN     SITEBIN  VENDORBIN
              SCRIPT  SITESCRIPT  VENDORSCRIPT
              MAN1DIR SITEMAN1DIR VENDORMAN1DIR
              MAN3DIR SITEMAN3DIR VENDORMAN3DIR
             );
}


=head3 libscan

  my $wanted = $self->libscan($path);

Takes a path to a file or dir and returns an empty string if we don't
want to include this file in the library.  Otherwise it returns the
the $path unchanged.

Mainly used to exclude version control administrative directories
and base-level F<README.pod> from installation.

=cut

sub libscan {
    my($self,$path) = @_;

    if ($path =~ m<^README\.pod$>i) {
        warn "WARNING: Older versions of ExtUtils::MakeMaker may errantly install $path as part of this distribution. It is recommended to avoid using this path in CPAN modules.\n";
        return '';
    }

    my($dirs,$file) = ($self->splitpath($path))[1,2];
    return '' if grep /^(?:RCS|CVS|SCCS|\.svn|_darcs)$/,
                     $self->splitdir($dirs), $file;

    return $path;
}


=head3 platform_constants

    my $make_frag = $mm->platform_constants

Returns a make fragment defining all the macros initialized in
init_platform() rather than put them in constants().

=cut

sub platform_constants {
    return '';
}

=head3 post_constants (o)

Returns an empty string per default. Dedicated to overrides from
within Makefile.PL after all constants have been defined.

=cut

sub post_constants {
    "";
}

=head3 post_initialize (o)

Returns an empty string per default. Used in Makefile.PLs to add some
chunk of text to the Makefile after the object is initialized.

=cut

sub post_initialize {
    "";
}

=head3 postamble (o)

Returns an empty string. Can be used in Makefile.PLs to write some
text to the Makefile at the end.

=cut

sub postamble {
    "";
}

=begin private

=head3 _PREREQ_PRINT

    $self->_PREREQ_PRINT;

Implements PREREQ_PRINT.

Refactored out of MakeMaker->new().

=end private

=cut

sub _PREREQ_PRINT {
    my $self = shift;

    require Data::Dumper;
    my @what = ('PREREQ_PM');
    push @what, 'MIN_PERL_VERSION' if $self->{MIN_PERL_VERSION};
    push @what, 'BUILD_REQUIRES'   if $self->{BUILD_REQUIRES};
    print Data::Dumper->Dump([@{$self}{@what}], \@what);
    exit 0;
}


=begin private

=head3 _PRINT_PREREQ

  $mm->_PRINT_PREREQ;

Implements PRINT_PREREQ, a slightly different version of PREREQ_PRINT
added by Redhat to, I think, support generating RPMs from Perl modules.

Should not include BUILD_REQUIRES as RPMs do not include them.

Refactored out of MakeMaker->new().

=end private

=cut

sub _PRINT_PREREQ {
    my $self = shift;

    my $prereqs= $self->{PREREQ_PM};
    my @prereq = map { [$_, $prereqs->{$_}] } keys %$prereqs;

    if ( $self->{MIN_PERL_VERSION} ) {
        push @prereq, ['perl' => $self->{MIN_PERL_VERSION}];
    }

    print join(" ", map { "perl($_->[0])>=$_->[1] " }
                 sort { $a->[0] cmp $b->[0] } @prereq), "\n";
    exit 0;
}


=begin private

=head3 _perl_header_files

  my $perl_header_files= $self->_perl_header_files;

returns a sorted list of header files as found in PERL_SRC or $archlibexp/CORE.

Used by perldepend() in MM_Unix and MM_VMS via _perl_header_files_fragment()

=end private

=cut

sub _perl_header_files {
    my $self = shift;

    my $header_dir = $self->{PERL_SRC} || $ENV{PERL_SRC} || $self->catdir($Config{archlibexp}, 'CORE');
    opendir my $dh, $header_dir
        or die "Failed to opendir '$header_dir' to find header files: $!";

    # we need to use a temporary here as the sort in scalar context would have undefined results.
    my @perl_headers= sort grep { /\.h\z/ } readdir($dh);

    closedir $dh;

    return @perl_headers;
}

=begin private

=head3 _perl_header_files_fragment ($o, $separator)

  my $perl_header_files_fragment= $self->_perl_header_files_fragment("/");

return a Makefile fragment which holds the list of perl header files which
XS code depends on $(PERL_INC), and sets up the dependency for the $(OBJECT) file.

The $separator argument defaults to "". MM_VMS will set it to "" and MM_UNIX to "/"
in perldepend(). This reason child subclasses need to control this is that in
VMS the $(PERL_INC) directory will already have delimiters in it, but in
UNIX $(PERL_INC) will need a slash between it an the filename. Hypothetically
win32 could use "\\" (but it doesn't need to).

=end private

=cut

sub _perl_header_files_fragment {
    my ($self, $separator)= @_;
    $separator ||= "";
    return join("\\\n",
                "PERL_HDRS = ",
                map {
                    sprintf( "        \$(PERL_INCDEP)%s%s            ", $separator, $_ )
                } $self->_perl_header_files()
           ) . "\n\n"
           . "\$(OBJECT) : \$(PERL_HDRS)\n";
}


=head1 AUTHOR

Michael G Schwern <schwern@pobox.com> and the denizens of
makemaker@perl.org with code from ExtUtils::MM_Unix and
ExtUtils::MM_Win32.


=cut

1;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              non interautivu enxamás entrugárate.
Extended_description-be.utf-8: Пакеты, што выкарыстоўваюць debconf для наладак, маюць агульны выгляд. Вы можаце вылучыць тып карыстальніцкага інтэрфейсу, з якім будзеце працаваць.\n\nДыялогавае кіраванне ёсць поўнаэкранным сімвальным інтэрфейсам, а кіраванне чытаннем радкоў выкарыстоўвае больш традыцыйную схему інтэрфейсу простага тэксту, і gnome- і kde-кіраванні ёсць навейшымі X-інтэрфейсамі, што запускаюцца ў адпаведнай графічнай сістэме (але могуць быць выкарыставаны ў любым асяроддзі X). Кіраванне рэдактарам дазваляе вам наладжваць рэчы, выкарыстоўвая ваш улюбёны тэкставы рэдактар. Неінтэрактыўнае кіраванне ніколі не задае вам ніякіх пытанняў.
Extended_description-bg.utf-8: Пакетите, които използват debconf за настройване, споделят един и същи изглед и начин на работа. Можете да изберете вида на потребителския интерфейс, който да се използва при настройване.\n\nИнтерфейсът „dialog“ е пълноекранен знаково-ориентиран интерфейс, докато интерфейсът „readline“ използва традиционния текстов интерфейс, а „gnome“ и „kde“ използват съвременни графични интерфейси, подходящи за съответните работни плотове, но могат да се използват и в други графични среди. Интерфейсът „редактор“ позволява настройване чрез редактиране с текстов редактор. Интерфейсът „без намеса“ никога не задава въпроси.
Extended_description-bn.utf-8: যে সকল প্যাকেজ কনফিগারেশনের জন্য debconf ব্যবহার করে তারা একই রকম চেহারা ধারন করে। তারা কি ধরনের ব্যবহারকারী ইন্টারফেস ব্যবহার করবে তা আপনি নির্বাচন করে দিতে পারেন।\n\nডায়ালগ ফ্রন্টএন্ড একটি পূর্ণ পর্দা, অক্ষর ভিত্তিক ইন্টারফেস, কিন্তু রিডলাইন ফ্রন্টএন্ড অধিক সনাতন সরল টেক্সট ইন্টারফেস ব্যবহার করে, এবং জিনোম ও কেডিই ফ্রন্টএন্ড উভয়ই আধুনিক X ইন্টারফেস, যা ডেস্কটপে মানানসই হয় (কিন্তু যেকোন X এনভায়রনমেন্টে ব্যবহার করা যেতে পারে)। সম্পাদক ফ্রন্টএন্ড আপনাকে আপনার পছন্দসই টেক্সট সম্পাদকের মাধ্যমে সবকিছু কনফিগার করতে দেবে। ক্রিয়া-প্রতিক্রিয়াহীন ফ্রন্টএন্ড আপনাকে কখনই কোন প্রশ্ন করবে না।
Extended_description-bs.utf-8: Paketi koji koriste debconf za konfiguraciju dijele zajednički izgled i način podešavanja. Možete odabrati tip korisničkog interfejsa koji će koristiti.\n\nDijaloški frontend je cijeloekranski, znakovno bazirani interfejs, dok readline frontend koristi tradicionalniji čisti tekstualni interfejs, dok su gnome i kde frontends moderni X interfejsi, koji nadopunjavaju respektivne desktope (ali se mogu koristiti u bilo kojem X okruženju). Uređivački frontend vam omogućuje da podesite stvari koristeći vaš omiljeni uređivač teksta. Neinteraktivni frontend nikad ne postavlja pitanja.
Extended_description-ca.utf-8: Els paquets que utilitzen debconf per a configurar-se comparteixen un aspecte comú. Podeu triar el tipus d'interfície d'usuari que voleu que empren.\n\n«dialog» és una interfície de text a pantalla completa, mentre que «readline» és més tradicional, en text simple, i tant «gnome» com «kde» són interfícies modernes per a X, que s'integren als escriptoris corresponents (tot i que es poden utilitzar en qualsevol entorn d'X). La interfície «editor» us permet configurar el sistema utilitzant el vostre editor preferit. La interfície «no interactiva» no fa cap pregunta.
Extended_description-cs.utf-8: Balíky, které pro svou konfiguraci využívají debconf, používají stejný vzhled a ovládání. Nyní si můžete zvolit typ uživatelského rozhraní, které budou používat.\n\nDialog je celoobrazovkové textové rozhraní, readline používá tradiční textové prostředí a gnome s kde jsou moderní grafická rozhraní (samozřejmě je můžete použít v libovolném jiném X prostředí). Editor vás nechá nastavit věci prostřednictvím vašeho oblíbeného textového editoru. Neinteraktivní rozhraní se nikdy na nic neptá.
Extended_description-cy.utf-8: Mae pecynnau sy'n defnyddio debconf ar gyfer cyfluniad yn rhannu edrychiad a teimlad cyffredin. Fe allwch chi ddewis y math o ryngwyneb maent yn ddefnyddio.\n\nMae pen blaen dialog yn ryngwyneb sgrîn-lawn testun graffigol, tra fod y pen blaen readline yn defnyddio rhyngwyneb testun plaen mwy traddodiadol, tra fod pen blaen gnome a kde yn ryngwynebau X modern, yn gweddu i'r pen bwrdd perthnasol (ond gellir ei defnyddio mewn unrhyw amgylchedd X). Mae'r rhyngwyneb golygydd yn eich caniatau i gyflunio pethau gan ddefnyddio eich hoff olygydd testun. Nid yw'r pen blaen an-rhyngweithiol yn gofyn unrhyw gwestiynau o gwbl.
Extended_description-da.utf-8: Pakker der bruger debconf til opsætning, fremtræder på samme måde. Du kan vælge hvilken brugerflade de skal bruge.\n\nDialog er en fuldskærms, tekstbaseret brugerflade, mens readline er en mere traditionel tekstbrugerflade. Både gnome og kde er moderne X-brugerflader. Editor lader dig svare på spørgsmålene via din foretrukne editor. Ikke-interaktivt brugerflade vil aldrig stille dig spørgsmål.
Extended_description-de.utf-8: Pakete, die Debconf für die Konfiguration verwenden, haben ein gemeinsames »look and feel«. Sie können wählen, welche Benutzerschnittstelle sie nutzen.\n\nDie Dialog-Oberfläche nutzt eine zeichen-basierte Vollbildschirmdarstellung, während die Readline-Oberfläche eine eher traditionelle einfache Textschnittstelle verwendet. Die GNOME- wie auch die KDE-Oberfläche sind moderne X-Schnittstellen, die in den jeweiligen Desktop eingepasst sind (aber in beliebigen X-Umgebungen verwendet werden können). Die Editor-Oberfläche gibt Ihnen die Möglichkeit, die Dinge mit Ihrem Lieblingseditor zu konfigurieren. Die nicht-interaktive Oberfläche stellt Ihnen keine Fragen.
Extended_description-dz.utf-8: རིམ་སྒྲིག་དོན་ལུ་debconf ལག་ལེན་འཐབ་མི་ཐུམ་སྒྲིལ་ཚུ་གིས་ ཐུན་མོང་གི་མཐོང་སྣང་དང་ཚོར་སྣང་ རུབ་སྤྱོད་འབདཝ་ཨིན། ཁྱོད་ཀྱིས་ ཁོང་གིས་ལག་ལེན་འཐབ་པའི་ལག་ལེན་པ་ངོས་འདྲ་བའི་དབྱེ་བ་ སེལ་འཐུ་འབད།\n\nལྷག་ཐིག་གདོང་མཐའ་གིས་ སྔར་སྲོལ་ཚིག་ཡིག་ཉག་རྐྱང་གི་ངོས་འདྲ་བ་ལེ་ཤ་ཅིག་ ལག་ལེན་འཐབ་ཨིནམ་དང་ཇི་ནོམ་དང་ཀེ་ཌི་ཨི་གདོང་མཐའ་གཉིས་ཆ་ར་ དེང་སང་གི་ ཨེགསི་ ངོོོས་འདྲ་བ་ཚུ་ཨིན་ མ་ལྟོས་པའི་ཌེཀསི་ཊོཔསི་ ཚུད་སྒྲིག་འབད་བའི་སྐབས་ལུ་(དེ་འབདཝ་ད་ ཨེགསི་ མཐའ་འཁོར་གང་རུང་ཅིག་ནང་ ལག་ལེན་འཐབ་འཐབ་འོང་) ཌའི་ལོག་གདོང་མཐའ་འདི་ གསལ་གཞི་གང་བ་དང་ ཡིག་འབྲུ་ལུ་གཞི་བཞག་པའི་ངོས་འདྲ་བ་ཨིན། ཞུན་དགཔ་གདོང་མཐའ་གིས་ཁྱོད་ལུ་ ཁྱོའ་རང་གིས་དགའ་མི་ ཚིག་ཡིག་ཞུན་དགཔ་ལག་ལེན་གྱི་ཐོག་ལས་ ཅ་ལ་དེ་ཚུ་རིམ་སྒྲིག་འབད་བཅུགཔ་ཨིན། ཕན་ཚུན་འབྲེལ་ལྡན་མ་ཡིན་པའི་གདོང་མཐའ་གིས་ ནམ་ར་ཨིན་རུང་ འདྲི་བ་ག་ཅི་ཡང་མི་འདྲིཝ་ཨིན།
Extended_description-el.utf-8: Τα πακέτα που χρησιμοποιούν το debconf για τη ρύθμισή τους έχουν μια κοινή εμφάνιση και "αίσθηση". Μπορείτε να επιλέξετε τον τύπο διεπαφής χρήστη που θα χρησιμοποιούν.\n\nΟ διαλογικός τρόπος εμφανίζει τις ερωτήσεις σε μία πλήρη οθόνη κονσόλας, ενώ η γραμμή εντολών (readline) χρησιμοποιεί απλό κείμενο, και αμφότεροι οι τρόποι αλληλεπίδρασης gnome και kde χρησιμοποιούν τα αντίστοιχα περιβάλλοντα (ή ακόμη και διαφορετικά περιβάλλοντα X) για να απεικονίζουν τις ερωτήσεις με γραφικό τρόπο. Ο κειμενογράφος σας επιτρέπει να παραμετροποιήσετε το πακέτο χρησιμοποιώντας τον προτιμώμενο επεξεργαστή κειμένου σας. Ο μη διαλογικός τρόπος δεν εμφανίζει καμία ερώτηση.
Extended_description-eo.utf-8: Pakoj kiuj uzas debconf por agordo kunhavas komunan aspekton. Vi povas elekti la tipon de interfaco kiun ili uzos.\n\nLa interfaco Dialog estas tutekrana, signo-aspekta interfaco, dum la interfaco Readline uzas pli tradician pur-tekstan interfacon, kaj la interfacoj Gnome kaj Kde estas modernaj X-interfacoj, konformaj al la respektivaj labortabloj (sed ili uzeblas en iu ajn X-medio). La interfaco Redaktilo ebligas akomodi aferojn per via preferata teksto-redaktilo. La Neinteraga interfaco neniam demandos vin pri io ajn.
Extended_description-es.utf-8: Los paquetes que usan debconf para configurarse comparten un aspecto común. Puede elegir el tipo de interfaz de usuario que quiere que usen.\n\nDialog es una interfaz de texto a pantalla completa, mientras que la de readline es más tradicional, de sólo texto, y gnome y kde son modernas interfaces para X adaptadas a cada uno de dichos escritorios (aunque pueden usarse en cualquier entorno gráfico). Editor le permite configurar el sistema usando su editor favorito. El interfaz no interactivo no hace ninguna pregunta.
Extended_description-et.utf-8: Seadistamiseks debconf'i kasutavatel pakkidel on ühtne välimus ja tunnetus. Võid valida nende poolt kasutatava kasutajaliidese.\n\nDialoog on täis-ekraani, tähepõhine liides, samas kui readline on traditsioonilisem vaba tekstiga liides. Nii kde kui ka gnome on moodsad X-liidesed, sobides vastavate töölaudadega (kuigi neid võib kasutad igas X keskkonnas). Redaktoriliides võimaldab seadistust oma lemmik tekstiredaktori aknast. Mitteinteraktiivne liides ei küsi iial küsimusi.
Extended_description-eu.utf-8: Konfiguratzeko debconf erabiltzen duten paketeek itxura eta portaera bateratu bat dute. Zein interfaze mota erabili aukeratu dezakezu.\n\nElkarrizketa pantaila osoko karakteretan oinarritutako interfaze bat da, Komando lerroa berriz testu laueko ohizko interfaze bat da. bai gnome eta bai kde interfazeak X-etan oinarritutako eta mahaigain horretarako prestaturik daude (naiz edozein X ingurunetan erabil daitezke). Editoreak konfiguraketak zure lehenetsitako testu editorea erabiliaz egingo ditu. Ez-interaktiboak ez dizu inoiz galderarik egingo.
Extended_description-fa.utf-8: بشته هایی که از debconf برای پیکربندی استفاده می کنند، شکل و حس مشترکی دارند. شما می توانید رابط کاربری که برای آنها مورد استفاده قرار می گیرد را انتخاب کنید.\n\nرابط dialog یک رابط کاربری تمام صفحه بر مبنای کاراکتر است، در حالی که readline بیشتر از رابط کاربری متنی استفاده می کند، و gnome و kde رابط های ،رابط کاربری X هستند که میزکارهای مناسبی را در اختیار می گذارند (اما ممکن است هر کدام از محیط های تحت X استفاده شود). ویرایشکر رابط به شما اجازه می دهد تا چیز ها را با ویرایشگر متن مورد علاقه خود ویرایش کنید. رابط های غیر محاوره ای هیچگاه از شما سؤالی نمی پرسند.
Extended_description-fi.utf-8: Debconf yhdenmukaistaa sitä käyttävien pakettien asetuskäyttöliittymän. Voit itse valita mieluisesi liittymän muutamasta vaihtoehdosta.\n\nValintaikkuna on ruudun täyttävä merkkipohjainen liittymä, kun taas readline on perinteisempi pelkkää tekstiä käyttävä liittymä. Sekä Gnome että KDE ovat nykyaikaisia X-pohjaisia liittymiä. Teksturi käyttää asetusten säätöön lempiteksturiasi. Ei-vuorovaikutteinen liittymä ei koskaan kysy kysymyksiä.
Extended_description-fr.utf-8: Les paquets utilisant debconf pour leur configuration ont une interface et une ergonomie communes. Vous pouvez choisir leur interface utilisateur.\n\n« Dialogue » est une interface couleur en mode caractère et en plein écran, alors que l'interface « Readline » est une interface plus traditionnelle en mode texte. Les interfaces « Gnome » et « KDE » sont des interfaces X modernes, adaptées respectivement à ces environnements (mais peuvent être utilisées depuis n'importe quel environnement X). L'interface « Éditeur » vous permet de faire vos configurations depuis votre éditeur favori. Si vous choisissez « Non-interactive », le système ne vous posera jamais de question.
Extended_description-ga.utf-8: Tá cosúlacht ag na pacáistí a úsáideann debconf lena chéile.  Is féidir leat cineál an chomhéadain úsáideora anseo.\n\nIs comhéadan lánscáileáin bunaithe ar charachtair é an comhéadan 'dialóg', agus is comhéadan téacs níos traidisiúnta é 'gnáth-théacs'.  Is comhéadain ghrafacha nua-aimseartha iad na comhéadain 'gnome' agus 'kde', oiriúnaithe do na deasca sin faoi seach (ach atá inúsáidte i dtimpeallacht X ar bith). Ligeann an comhéadan 'eagarthóir' duit gach rud a chumrú san eagarthóir téacs is ansa leat. Ní chuireann an comhéadan 'neamh-idirghníomhach' ceist ar bith ort.
Extended_description-gl.utf-8: Os paquetes que empregan debconf para a configuración comparten unha aparencia común. Pode escoller o tipo de interface de usuario que empregan.\n\nA interface dialog é unha interface de pantalla completa en modo texto, mentres que a interface readline emprega unha interface de texto simple máis traicional; as interfaces gnome e kde son interfaces modernas de X, que encaixan cos respectivos escritorios (pero que se poden empregar en calquera ambiente X). A interface editor permítelle configurar as cousas empregando o seu editor de texto favorito. A interface non interactiva nunca lle fai preguntas.
Extended_description-gu.utf-8: જે પેકેજો રુપરેખાંકન માટે ડેબકોન્ફ વાપરે છે તેઓ સમાન દેખાવ ધરાવે છે. તમે તેઓ જે દેખાવ વાપરે છે તે પસંદ કરી શકો છો.\n\nસંવાદ દેખાવ એ પૂર્ણ-સ્ક્રિન, અક્ષર પર આધારિત દેખાવ છે, જ્યારે રીડલાઈન દેખાવ પરંપરાગત સામાન્ય લખાણ દેખાવ વાપરે છે, અને ગ્નોમ અને કેડીઈ દેખાવો તાજેતરનાં X દેખાવો છે, જે સંબંધિત ડેસ્કટોપ્સમાં મેળ ખાય છે (પણ કોઈપણ X વાતાવરણમાં ઉપયોગી છે). સંપાદક દેખાવ તમને તમારા પસંદગીનાં સંપાદકમાં રુપરેખાંકન કરવા દેશે. અસક્રિય દેખાવ તમને ક્યારેય પ્રશ્નો પૂછશે નહી.
Extended_description-he.utf-8: חבילות משתמשות ב-debconf לקונפיגורציה בן בעלות מראה וממשק משותף. תוכל לבחור את סוג הממשק משתמש שבו הן ישתמשו.\n\nממשק הדיאלוג נפרש על מסך מלא, ומובסס על ממשק תווי, בזמן שממשק ה-readline משתמש בממשק טקסט יותר מסורתי. גם ממשקי גנום ו-KDE הם ממשקים גרפיים מודרניים. ממשק העורך מאפשר לך להגדיר דברים דרך עורך הטקסט החביב עליך. והממשק הלא אינטראקטיבי פשוט אף פעם לא שואל אותך שאלות.
Extended_description-hi.utf-8: वे पैकेज जो कॉन्फ़िगरेशन के लिए डीबीकॉन्फ का इस्तेमाल करते हैं उनमें एक सामान्य रूप होता है. उनके द्वारा इस्तेमाल में लिए जाने वाले उपयोक्ता इंटरफ़ेस को आप चुन सकते हैं.\n\nसंवाद फ्रन्टएण्ड पूरे स्क्रीन पर अक्षर आधारित इंटरफेस है, जबकि रीडलाइन फ्रन्टएण्ड में पारंपरिक पाठ इंटरफेस इस्तेमाल होता है तथा गनोम व केडीई के फ्रन्टएण्ड में आधुनिक X इंटरफेस हैं जो संबंधित डेस्कटॉप में फिट होते हैं (परंतु किसी भी X वातावरण में इस्तेमाल में लिए जा सकते हैं). संपादन फ्रन्टएण्ड आपको पाठ संपादक के जरिए बहुत सी चीज़ों को कॉन्फ़िगर करने का अवसर प्रदान करता है. नॉनइंटरेक्टिव इंटरफ़ेस आपको कभी भी कोई प्रश्न नहीं पूछता है.
Extended_description-hr.utf-8: Paketi koji koriste debconf za postavke dijele zajednički izgled i način rada. Možete odabrati vrstu korisničkog sučelja koji oni koriste.\n\nSučelje 'Dialog' je tekstualno preko cijelog ekrana, dok je sučelje 'Readline' više tradicionalno tekstualno sučelje. I 'Gnome' i 'KDE' sučelja su moderna X sučelja, koja se uklapaju u odgovarajuća grafička radna okruženja (iako se mogu koristiti u bilo kojem X okruženju). Sučelje 'Editor' vam omogućuje podešavanje stvari u vašem omiljenom programu za uređivanje teksta. Neinteraktivno sučelje nikad ne pita nikakva pitanja.
Extended_description-hu.utf-8: A debconf-ot használó csomagok egységes felületet használnak. Itt lehet kiválasztani, melyik legyen az.\n\nA párbeszéd felület egy teljes-képernyős, karakteres felület, az egysoros viszont a sokkal hagyományosabb egyszerű szöveges felület, a gnome és kde felületek pedig korszerű X felületek, melyek e 2 munkakörnyezetbe illenek (de bármilyen X környezetben használhatók). A szerkesztő felülettel a kedvenc szövegszerkesztővel lehet dolgozni. A néma felület soha nem kérdez.
Extended_description-id.utf-8: Paket-paket yang dikonfigurasi lewat debconf memakai antar muka yang seragam. Anda dapat memilih jenis antarmuka pengguna yang dipakai.\n\nAntarmuka dialog berbasis karakter layar penuh, sementara bacabaris memakai teks yang lebih tradisional, baik gnome dan kde menggunakan antar muka grafis (X). Antarmuka penyunting memungkinkan anda mengkonfigurasi sesuatu dengan penyunting naskah kesayangan anda. Antarmuka tak-iteraktif tak pernah menanyakan apapun.
Extended_description-is.utf-8: Forrit sem nota debconf sem stillingaviðmót deila með sér svipuðu útliti og áferð. Þú getur valið hverskonar notandaviðmót þau nota.\n\nViðmót samskiptagluggans er textaviðmót á heilskjá (DOS-líkt), á meðan leslína er meira í ætt við hefðbundna skipanalínu. Bæði GNOME og KDE viðmótin eru nútíma gluggaviðmót sem samsvara samnefndum skjáborðsumhverfum (en sem hægt er að nota í hvaða gluggaumhverfi sem er). Ritilsviðmótið gerir þér kleift að stilla hluti með því að nota þann ritil sem þér finnst þægilegast að vinna með. Ógagnvirkt viðmót spyr þig ekki neinna spurninga.
Extended_description-it.utf-8: I pacchetti che usano debconf per la configurazione condividono un aspetto comune. È possibile selezionare il tipo di interfaccia utente da usare.\n\nIl fronted "dialog" è un'interfaccia a schermo pieno a caratteri mentre il frontend "readline" usa un'interfaccia più tradizionale, in puro testo. Entrambi i frontend "gnome" e "kde" sono interfacce moderne basate su X che si adattano ai rispettivi ambienti grafici (ma possono essere usati in qualsiasi ambiente X). Il frontend "editor" permette di eseguire la configurazione utilizzando il proprio editor preferito. Il frontend "noninteractive" non pone alcuna domanda.
Extended_description-ja.utf-8: 設定に debconf を用いるパッケージは、共通のルック＆フィールを用います。どの種類のユーザインターフェイスを用いるかを選んでください。\n\n「ダイアログ」は全画面の文字ベースのインターフェイスです。「readline」はより伝統的なプレーンテキストのインターフェイスです。「gnome」と「kde」は近代的な X のインターフェイスで、それぞれのデスクトップに適しています (ほかの X 環境で利用することもできます)。「エディタ」を用いるとあなたの好きなテキストエディタを用いることができます。「非対話的」を選ぶとまったく質問をしなくなります。
Extended_description-kk.utf-8: Бапталу үшін debconf қолданылатын дестелерде бапталу түрі бірдей болады. Олар қолданатын интерфейсті таңдай аласыз.\n\nСұхбат интерфейсі толық экрандық, таңбалық құралы болып келеді, жолды оқу дегеніміз - дәстүрлі қалыпты мәтіндік интерфейс, gnome мен kde нұсқалардың екеуі де жаңа, X интерфейсіне негізделген, түрлі X жұмыс үстел орталарында қолданыла алады. Түзетуші - сізге нәрселерді таңдаулы мәтін түзетуші қолданбасы көмегімен баптауға мүмкіндік береді. Интерактивті емес нұсқасы сізге ешқашан да сұрақтарды қоймайды.
Extended_description-km.utf-8: កញ្ចប់​ដែល​ប្រើ​ debconf សម្រាប់​ការកំណត់​រចនាសម្ព័ន្ធ ចែករំលែក​រូបរាង​និង​អារម្មណ៍ ។ អ្នក​អាច​ជ្រើស​ប្រភេទ​ចំណុច​ប្រទាក់​អ្នក​ប្រើ​ដែល​ពួក​គេ​ប្រើ ។\n\nប្រអប់​ផ្នែក​ខាងមុខ​ គឺអេក្រង់ពេញមួយ តួអក្សរបានផ្អែកលើ​​​ចំណុច​ប្រទាក់​ នៅខណៈ​ពេល​ដែលបន្ទាត់​អាន​​ផ្នែក​ខាង​មុខ​ប្រើ​ចំណុច​ប្រទាក់​អត្ថបទ​ធម្មតាដែលចាស់ជាង ហើយផ្នែកខាងមុខ​ gnome និង​ kde ជា​ចំណុច​ប្រទាក់​ X ដែលថ្មីទំនើប, ដែលសម​ត្រឹមត្រូវទៅនឹង​ផ្ទៃតុ​​ (ប៉ុន្តែ​ ប្រហែល​ត្រូវបាន​ប្រើនៅក្នុង​បរិដ្ឋាន X ណាមួយ) ។ ផ្នែកខាងមុខ​នៃ​កម្មវិធី​និពន្ធ ​អនុញ្ញាត​ឲ្យ​អ្នក​កំណត់​រចនាសម្ព័ន្ធ​វត្ថុ​ដោយ​ប្រើកម្មវិធី​និពន្ធ​អត្ថបទ​ដែលអ្នក​ដែល​ចូលចិត្ត ។ ផ្ទៃខាងមុខ​ដែល​មិនមែនជា​អន្តរកម្ម ​មិន​ដែល​សួរ​សំណួរ​អ្នកឡើយ​ ។
Extended_description-ko.utf-8: 설정할 때 debconf를 사용하는 패키지는 비슷한 모양의 인터페이스를 사용합니다. 여기서 어떤 종류의 인터페이스를 사용할 지 선택할 수 있습니다.\n\n다이얼로그 프론트엔드는 문자 기반의 전체 화면 인터페이스이고, 리드라인 프론트엔드는 더 전통적인 일반 텍스트 인터페이스를 사용하고, 그놈과 KDE는 현대적인 X 인터페이스로 해당 데스크톱에 적합합니다 (하지만 X 환경에서만 사용할 수 있습니다). 편집기 프론트엔드는 본인이 자주 사용하는 텍스트 편집기를 이용해서 설정합니다. 물어보지 않음 프론트엔드의 경우 어떤 설정도 물어보지 않습니다.
Extended_description-lt.utf-8: Paketai, naudojantys „debconf“, konfigūracijai naudoja vienodą naudotojo sąsają. Galite pasirinkti Jums tinkamiausią sąsajos tipą.\n\nDialogai – tai visaekranė tekstinė sąsaja, o Tekstinė eilutė („Readline“) – labiau tradicinė tekstinė sąsaja. „Gnome“ ir „Kde“ yra šiuolaikinės grafinės naudotojo sąsajos, skirtos dirbti atitinkamose grafinėse aplinkose (bet gali būti naudojamos bet kurioje X aplinkoje). Tekstų redaktoriaus sąsaja leidžia atlikti konfigūravimą Jūsų mėgiamame tekstų redaktoriuje. Neinteraktyvi sąsaja niekuomet nepateiks Jums jokių klausimų.
Extended_description-lv.utf-8: Pakām, kas lieto debconf konfigurācijas jautājumu uzdošanai, ir vienota lietotāja saskarne. Lūdzu, izvēlieties, kādu lietotāja saskarnes tipu jūs vēlaties lietot.\n\nDialoga saskarne ir pilnekrāna teksta bāzēta saskarne, bet readline saskarne ir tradicionālāka tīra teksta rindu saskarne, savukārt gan Gnome gan KDE saskarnes lieto X grafisko vidi un ir piemērojami attiecīgajām darba vidēm (un var tik lietoti arī ārpus tām - jebkurā X vidē). Teksta redaktora saskarsme ļauj jums konfigurēt lietas, izmantojot jūsu iecienīto teksta redaktoru. Neinteraktīvā saskarne nekad neuzdod nekādus jautājumus.
Extended_description-mg.utf-8: Ny fonosana izay tefeny amin'ny alalan'ny debconf dia mitovy tarehy sy fihetsika. Afaka mifidy izany tarehy sy fihetsika izany ianao.\n\nThe dialog frontend is a full-screen, character based interface, while the readline frontend uses a more traditional plain text interface, and both the gnome and kde frontends are modern X interfaces, fitting the respective desktops (but may be used in any X environment). The editor frontend lets you configure things using your favorite text editor. The noninteractive frontend never asks you any questions.
Extended_description-mk.utf-8: Пакетите кои го користат debconf за конфигурација делат заеднички изглед. Може да го избереш типот на кориснички интерфејс кои ќе го користат.\n\nИнтерфејсот dialog  е интерфејс на цел екран со текст и графика, додека readline интерфејсот е потрадиционален текстуален интерфејс,a гном и кде интерфејсите се модерни Х графички интерфејси. Editor интерфејсот ти овоможува да ги конфигурираш работите со твојот омилен тексутален уредувач. Неинтерактивниот интерфејст никогаш не те прашува никакви прашања.
Extended_description-ml.utf-8: ക്രമീകരണത്തിനായി ഡെബ്കോണ്‍ഫ്  ഉപയോഗിക്കുന്ന പാക്കേജുകള്‍ ഒരു പൊതുവായ കാഴ്ചയും അനുഭവവും നല്കുന്നു. അവ ഉപയോഗിക്കുന്ന ഇന്റര്‍ഫേസിന്റെ തരം നിങ്ങളള്‍ക്ക് തിരഞ്ഞെടുക്കാം.\n\nഡയലോഗ് ഫ്രണ്ടെന്റ് ഒരു ഫുള്സ്ക്രീന്‍
Extended_description-mr.utf-8: संरचनेसाठी डेबकॉन्फ एकत्रितरित्या वापरणारी पॅकेजेस दिसावयास व वापरण्यास सारखी आहेतवापरकर्ता त्यामध्ये उपलब्ध असणारा कोणताही आंतराफलक वापरण्यासाठी निवडु शकतो\n\nसामोरा येणारा संवादफलक संपूर्ण स्क्रीन व्यापणारा व अक्षराधारित असून वाचन ओळीचा आंतराफलक मात्र साध्या मजकूरावर आधारित आहे तर जीनोम आणि केडीईचे संवादफलक आधुनिक X पध्दतीवर आधारलेले आंतराफलक आहेत जे संपूर्ण डेस्कटॉप व्यापतात (परंतू त्यांचा वापर तुम्ही फक्त X वरील आधारित परिवेशांमध्येच करू शकता)। सामो-या येणा-या मजकूर लेखन संवादफलकामध्ये तुम्हाला तुमच्या आवडत्या संवाद लेखन साधनातील सुविधांनुसार संरचना करण्याचे स्वातंत्र्य देतो तर सामोरा येणारा संवादप्रक्रियाहीन संवादफलक तुम्हाला कोणतेही प्रश्न विचारीत नाही
Extended_description-nb.utf-8: Pakker som bruker debconf til innstillinger har felles utseende og oppførsel. Du kan velge hva slags brukerflate de bruker.\n\nDialog-flaten er et tegnbasert grensesnitt som bruker hele skjermen, mens readline-flaten er et mer tradisjonelt tekst-grensesnitt, og både Gnome og KDE er moderne X-brukerflater som passer de respektive skrivebordene (men kan brukes i alle X-miljøer). Redigeringen gjør at du kan sette opp innstillingene med det redigeringsprogrammet du liker best. Den ikke-interaktive flaten stiller aldri noen spørsmål.
Extended_description-ne.utf-8: कनफिगरेसनको लागि debconf प्रयोग गर्ने प्याकेजहरुले साझा हेराई र अनुभव बाँड्छ । तपाईँ तिनीहरुले प्रयोग गर्ने प्रयोगकर्ता इन्टरफेसको प्रकार चयन गर्न सक्नुहुन्छ ।\n\nसंवाद सामने भएको पूरा पर्दामा आधारित क्यारेक्टर इन्टरफेस हो, जब सामने भएको पढ्ने पंक्तिले धेरै पुरानो खाली पाठ इन्टरफेस प्रयोग गर्छ, सम्बन्धित डेस्कटपहरू फिट गर्दा ( तर कुनै X परिवेशमा प्रयोग हुन सक्ने) दुवै जिनोम र kde सामनेहरू आधुनिक X इन्टरफेसहरू हुन्छन् । सामुने भएको सम्पादकले तपाईँलाई मन परेको पाठ सम्पादक प्रयोग गरेर चीजहरू कनफिगर गर्नु दिन्छ । सामुने पारस्पारिक क्रियात्मक नभएकाहरुले तपाईँलाई कुनै प्रश्नहरू सोधदैन ।ुने दन
Extended_description-nl.utf-8: Alle pakketten die voor configuratie gebruik maken van debconf werken op dezelfde manier. U kunt hier het type interface instellen dat door deze programma's gebruikt zal worden.\n\nDe dialog-frontend is een niet-grafische (karaktergebaseerde) interface die het volledige scherm overneemt, terwijl de ReadLine-frontend in een meer tradionele tekstinterface voorziet. De KDE en Gnome frontends zijn moderne grafische interfaces, die bij de betreffende desktops horen (maar in elke X-omgeving werken). De editor-frontend laat toe om dingen in te stellen met behulp van uw favoriete tekst-editor. De niet-interactieve frontend, tenslotte vraagt helemaal niks.
Extended_description-no.utf-8: Pakker som bruker debconf til innstillinger har felles utseende og oppførsel. Du kan velge hva slags brukerflate de bruker.\n\nDialog-flaten er et tegnbasert grensesnitt som bruker hele skjermen, mens readline-flaten er et mer tradisjonelt tekst-grensesnitt, og både Gnome og KDE er moderne X-brukerflater som passer de respektive skrivebordene (men kan brukes i alle X-miljøer). Redigeringen gjør at du kan sette opp innstillingene med det redigeringsprogrammet du liker best. Den ikke-interaktive flaten stiller aldri noen spørsmål.
Extended_description-pa.utf-8: ਪੈਕੇਜ, ਜੋ ਕਿ debconf ਨੂੰ ਇੱਕ ਸਾਂਝੀ ਦਿੱਖ ਅਤੇ ਰਵੱਈਆ ਸਾਂਝਾ ਕਰਨ ਲਈ ਸੰਰਚਿਤ ਕੀਤੇ ਜਾਂਦੇ ਹਨ। ਤੁਸੀਂ ਉਹਨਾਂ ਵਲੋਂ ਵਰਤੇ ਜਾਣ ਵਾਲੇ ਉਪਭੋਗੀ ਇੰਟਰਫੇਸ ਦੀ ਕਿਸਮ ਚੁਣ ਸਕਦੇ ਹੋ।\n\nਇੱਕ ਵਾਰਤਾਲਾਪ ਦਿੱਖ ਪੂਰੇ ਪਰਦੇ ਉੱਤੇ, ਅੱਖਰ ਅਧਾਰਿਤ ਇੰਟਰਫੇਸ ਹੈ, ਜਦੋਂ ਉਪਭੋਗੀ ਵਲੋਂ ਪੁਰਾਣੇ ਪਾਠ ਇੰਟਰਫੇਸ ਰਾਹੀਂ ਇੰਪੁੱਟ ਲੈਂਦਾ ਹੈ, ਅਤੇ ਦੋਵੇਂ ਗਨੋਮ ਅਤੇ ਕੇਡੀਈ ਮੁੱਖ ਮਾਡਰਨ X ਇੰਟਰਫੇਸ ਹਨ, ਜੋਂ ਆਪਣੇ ਆਪਣੇ ਵੇਹੜਿਆਂ ਵਿੱਚ ਆਉਦੇ ਹਨ (ਪਰ ਹੋਰ X ਵਾਤਾਵਰਣ ਵਿੱਚ ਵੀ ਵਰਤੇ ਜਾ ਸਕਦੇ ਹਨ)। ਸੰਪਾਦਕ ਮੁੱਖ ਭੂਮੀ ਤੁਹਾਨੂੰ ਆਪਣਾ ਪਸੰਦੀਦਾ ਪਾਠ ਸੰਪਾਦਕ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਸਹਾਇਕ ਹੈ। ਨਾ-ਦਿਲ-ਖਿੱਚਵਾਂ ਤੁਹਾਨੂੰ ਕੋਈ ਸਵਾਲ ਨਹੀਂ ਪੁੱਛਦਾ ਹੈ।
Extended_description-pl.utf-8: Pakiety korzystające do konfiguracji z debconfa współdzielą jeden wygląd i sposób użycia. Możesz wybrać rodzaj interfejsu wykorzystywanego do tego.\n\nNakładka dialog jest pełnoekranowa i wyświetla menu w trybie tekstowym podczas gdy nakładka readline jest bardziej tradycyjnym interfejsem i korzysta ze zwykłego tekstu. Zarówno nakładka Gnome jak i Kde są nowoczesnymi interfejsami dostosowanymi do poszczególnych środowisk (ale mogą zostać użyte w jakimkolwiek środowisku X). Nakładka edytor pozwala konfigurować z wykorzystaniem ulubionego edytora tekstowego. Nakładka nieinteraktywna nigdy nie zadaje żadnych pytań.
Extended_description-pt.utf-8: Os pacotes que utilizam debconf para a configuração partilham um aspecto e comportamento idênticos. Você pode escolher o tipo de interface com o utilizador que eles utilizam.\n\nO frontend dialog é um interface de caracteres, de ecrã completo, enquanto que o frontend readline utiliza um interface mais tradicional de texto simples, e ambos os frontend gnome e kde são interfaces modernos com o X, cabendo nos respectivos desktop (embora possam ser utilizados em qualquer ambiente X). O frontend editor deixa-o configurar as coisas utilizando o seu editor de texto favorito. O frontend não-interactivo nunca pergunta quaisquer questões.
Extended_description-pt_br.utf-8: Pacotes que usam o debconf para configurações compartilham uma interface e um modo de usar comuns. Você pode selecionar o tipo de interface que eles usarão.\n\nA interface dialog é em tela cheia e baseada em texto, enquanto a interface readline usa uma interface mais tradicional de texto puro e as interfaces gnome e kde são interfaces X modernas, se adequando aos respectivos ambientes (mas podem ser usadas em qualquer ambiente X). A interface editor permite que você configure os pacotes usando seu editor de textos favorito. A interface não-interativa ("noninteractive") nunca faz perguntas a você.
Extended_description-ro.utf-8: Pachetele care folosesc debconf pentru configurare, sunt asemănătoare în aspect și comportament. Puteți selecta tipul de interfață utilizat de ele.\n\nInterfața dialog este o interfață în mod text, pe tot ecranul, în timp ce linia de comandă folosește o interfață în mod text, mai tradițională, și, atât interfața gnome cât și kde sunt interfețe moderne în X, care se încadrează în mediile respective (dar pot fi folosite în orice mediu X). Interfața editor vă permite sa configurați lucrurile folosind editorul de text preferat de dvs. Interfața non-interactivă nu vă întreabă niciodată nimic.
Extended_description-ru.utf-8: Пакеты, использующие debconf, обладают единообразным интерфейсом настройки. Вы можете выбрать наиболее подходящий.\n\nДиалоговый интерфейс представляет собой текстовое полноэкранное приложение, «командная строка» использует более традиционный простой текстовый интерфейс, а Gnome и Kde — современные X-интерфейсы, встроенные в соответствующие рабочие столы (но могут использоваться в любом X-окружении). Интерфейс «из текстового редактора» позволяет задавать настройки в вашем любимом редакторе. Пакетный интерфейс вообще избавляет от необходимости отвечать на вопросы.
Extended_description-si.utf-8: සැකසුම් සඳහා debconf හවුල් කරගන්නා සෑම පැකේජයක්ම පොදු පෙනුමක් දරයි. කරුණාකර ඒවා භාවිත කරන පරිශීලක අතුරුමුහුණත් වර්‍ගය තෝරන්න.\n\nසංවාද ඉදිරි ඉම, සම්පූර්ණ තිරැති, අක්‍ෂර මූලික අතුරුමුහුනතක් භාවිත කරන විට කියවීම් පේළි වඩා සාම්ප්‍රදායික පැතලි පෙළ අතුරුමුහුණතක් භාවිත කරයි, gnome හා kde යන ඉදිරි ඉම් දෙකම බොහෝ දර්ශක හා ගැලපෙන (ඕනෑම x පරිසරයක භාවිත වන) නූතන X අතුරුමුහුණත් වේ. සකසන ඉදිරි ඉම ඔබට කැමතිම පෙළ සකසනය භාවිතයෙන් සැකසුම් සිදු කිරීමට ඉඩ දෙයි. අන්තර්ක්‍රියාකාරී නොවන ඉදිරි ඉම ඔබෙන් කිසිවිට ප්‍රශ්න නොඅසයි.
Extended_description-sk.utf-8: Balíky, ktoré využívajú pre svoje nastavenie debconf, majú rovnaký vzhľad a ovládanie. Teraz si môžete zvoliť typ používateľského rozhrania, ktoré sa bude používať.\n\nDialóg je celoobrazovkové textové rozhranie, readline používa tradičné textové prostredie a gnome s kde sú moderné grafické rozhrania (samozrejme ich môžete použiť v ľubovoľnom inom X prostredí). Editor vám umožní úpravu nastavení pomocou vášho obľúbeného textového editora. Neinteraktívne rozhranie sa nikdy na nič nepýta.
Extended_description-sl.utf-8: Paketi, ki uporabljajo debconf za nastavitve si delijo enak uporabniški vmesnik in izgled. Nastavite lahko tip uporabniškega vmesnika, ki ga uporabljajo.\n\nVmesnik dialog je celozaslonski vmesnik, ki deluje v znakovnem načinu. Bralnovrstični (readline) vmesnik uporablja bolj tradicionalen tekstovni vmesnik. Tako Gnome kot KDE vmesnika sta sodobna X vmesnika, ki ustrezata vsak svojemu namizju (vendar ju je mogoče uporabljati v vsakem X okolju). Urejevalni vmesnik vam omogoča nastavljanje stvari s pomočjo vašega priljubljenega tekstovnega urejevalnika. Neinteraktiven vmesnik vas nikoli ne sprašuje.
Extended_description-sq.utf-8: Paketat që përdorin debconfg për konfigurim ndajnë një pamje dhe ndjesi të njëjtë. Ju mund të zgjidhni tipin e ndërfaqes së përdoruesit që ata përdorin.\n\nFrontend-i dialog është ndërfaqe në ekran të plotë, e bazuar në karaktere ndërsa frontend-i i linjës së leximit përdor një ndërfaqës të teksit të thjeshtë më tradicional dhe të dy frontend-et, gnome dhe kde, janë ndërfaqës X modern, qe u përmbahen desktopëve respektivë (por mund të përdoren në çdo mjedis X). Frontend-i editues të lejon të konfigurosh gjëra duke përdorur cdo editor teksti. Frontend-i jointeraktiv nuk të pyet asnjëherë për pyetje.
Extended_description-sr.utf-8: Пакети који користе debconf за конфигурацију користе заједнички интерфејс. Можете изабрати тип интерфејса за употребу.\n\nИнтерфејс у облику дијалога је текстуални који package ExtUtils::MM_Unix;

require 5.006;

use strict;
use warnings;

use Carp;
use ExtUtils::MakeMaker::Config;
use File::Basename qw(basename dirname);

our %Config_Override;

use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);

# If we make $VERSION an our variable parse_version() breaks
use vars qw($VERSION);
$VERSION = '7.64';
$VERSION =~ tr/_//d;

require ExtUtils::MM_Any;
our @ISA = qw(ExtUtils::MM_Any);

my %Is;
BEGIN {
    $Is{OS2}     = $^O eq 'os2';
    $Is{Win32}   = $^O eq 'MSWin32' || $Config{osname} eq 'NetWare';
    $Is{Dos}     = $^O eq 'dos';
    $Is{VMS}     = $^O eq 'VMS';
    $Is{OSF}     = $^O eq 'dec_osf';
    $Is{IRIX}    = $^O eq 'irix';
    $Is{NetBSD}  = $^O eq 'netbsd';
    $Is{Interix} = $^O eq 'interix';
    $Is{SunOS4}  = $^O eq 'sunos';
    $Is{Solaris} = $^O eq 'solaris';
    $Is{SunOS}   = $Is{SunOS4} || $Is{Solaris};
    $Is{BSD}     = ($^O =~ /^(?:free|net|open)bsd$/ or
                   grep( $^O eq $_, qw(bsdos interix dragonfly) )
                  );
    $Is{Android} = $^O =~ /android/;
    if ( $^O eq 'darwin' && $^X eq '/usr/bin/perl' ) {
      my @osvers = split /\./, $Config{osvers};
      $Is{ApplCor} = ( $osvers[0] >= 18 );
    }
}

BEGIN {
    if( $Is{VMS} ) {
        # For things like vmsify()
        require VMS::Filespec;
        VMS::Filespec->import;
    }
}


=head1 NAME

ExtUtils::MM_Unix - methods used by ExtUtils::MakeMaker

=head1 SYNOPSIS

  require ExtUtils::MM_Unix;

=head1 DESCRIPTION

The methods provided by this package are designed to be used in
conjunction with L<ExtUtils::MakeMaker>. When MakeMaker writes a
Makefile, it creates one or more objects that inherit their methods
from a package L<MM|ExtUtils::MM>. MM itself doesn't provide any methods, but
it ISA ExtUtils::MM_Unix class. The inheritance tree of MM lets operating
specific packages take the responsibility for all the methods provided
by MM_Unix. We are trying to reduce the number of the necessary
overrides by defining rather primitive operations within
ExtUtils::MM_Unix.

If you are going to write a platform specific MM package, please try
to limit the necessary overrides to primitive methods, and if it is not
possible to do so, let's work out how to achieve that gain.

If you are overriding any of these methods in your Makefile.PL (in the
MY class), please report that to the makemaker mailing list. We are
trying to minimize the necessary method overrides and switch to data
driven Makefile.PLs wherever possible. In the long run less methods
will be overridable via the MY class.

=head1 METHODS

The following description of methods is still under
development. Please refer to the code for not suitably documented
sections and complain loudly to the makemaker@perl.org mailing list.
Better yet, provide a patch.

Not all of the methods below are overridable in a
Makefile.PL. Overridable methods are marked as (o). All methods are
overridable by a platform specific MM_*.pm file.

Cross-platform methods are being moved into L<MM_Any|ExtUtils::MM_Any>.
If you can't find something that used to be in here, look in MM_Any.

=cut

# So we don't have to keep calling the methods over and over again,
# we have these globals to cache the values.  Faster and shrtr.
my $Curdir  = __PACKAGE__->curdir;
my $Updir   = __PACKAGE__->updir;


=head2 Methods

=over 4

=item os_flavor

Simply says that we're Unix.

=cut

sub os_flavor {
    return('Unix');
}


=item c_o (o)

Defines the suffix rules to compile different flavors of C files to
object files.

=cut

sub c_o {
# --- Translation Sections ---

    my($self) = shift;
    return '' unless $self->needs_linking();
    my(@m);

    my $command = '$(CCCMD)';
    my $flags   = '$(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE)';

    if ( $Is{ApplCor} ) {
        $flags =~ s/"-I(\$\(PERL_INC\))"/-iwithsysroot "$1"/;
    }

    if (my $cpp = $self->{CPPRUN}) {
        my $cpp_cmd = $self->const_cccmd;
        $cpp_cmd =~ s/^CCCMD\s*=\s*\$\(CC\)/\$(CPPRUN)/;
        push @m, qq{
.c.i:
	$cpp_cmd $flags \$*.c > \$*.i
};
    }

    my $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*.s') : '';
    push @m, sprintf <<'EOF', $command, $flags, $m_o;

.c.s :
	%s -S %s $*.c %s
EOF

    my @exts = qw(c cpp cxx cc);
    push @exts, 'C' if !$Is{OS2} and !$Is{Win32} and !$Is{Dos}; #Case-specific
    $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*$(OBJ_EXT)') : '';
    my $dbgout = $self->dbgoutflag;
    for my $ext (@exts) {
	push @m, "\n.$ext\$(OBJ_EXT) :\n\t$command $flags "
            .($dbgout?"$dbgout ":'')
            ."\$*.$ext" . ( $m_o ? " $m_o" : '' ) . "\n";
    }
    return join "", @m;
}


=item xs_obj_opt

Takes the object file as an argument, and returns the portion of compile
command-line that will output to the specified object file.

=cut

sub xs_obj_opt {
    my ($self, $output_file) = @_;
    "-o $output_file";
}

=item dbgoutflag

Returns a CC flag that tells the CC to emit a separate debugging symbol file
when compiling an object file.

=cut

sub dbgoutflag {
    '';
}

=item cflags (o)

Does very much the same as the cflags script in the perl
distribution. It doesn't return the whole compiler command line, but
initializes all of its parts. The const_cccmd method then actually
returns the definition of the CCCMD macro which uses these parts.

=cut

#'

sub cflags {
    my($self,$libperl)=@_;
    return $self->{CFLAGS} if $self->{CFLAGS};
    return '' unless $self->needs_linking();

    my($prog, $uc, $perltype, %cflags);
    $libperl ||= $self->{LIBPERL_A} || "libperl$self->{LIB_EXT}" ;
    $libperl =~ s/\.\$\(A\)$/$self->{LIB_EXT}/;

    @cflags{qw(cc ccflags optimize shellflags)}
	= @Config{qw(cc ccflags optimize shellflags)};

    # Perl 5.21.4 adds the (gcc) warning (-Wall ...) and std (-std=c89)
    # flags to the %Config, and the modules in the core should be built
    # with the warning flags, but NOT the -std=c89 flags (the latter
    # would break using any system header files that are strict C99).
    my @ccextraflags = qw(ccwarnflags);
    if ($ENV{PERL_CORE}) {
      for my $x (@ccextraflags) {
        if (exists $Config{$x}) {
          $cflags{$x} = $Config{$x};
        }
      }
    }

    my($optdebug) = "";

    $cflags{shellflags} ||= '';

    my(%map) =  (
		D =>   '-DDEBUGGING',
		E =>   '-DEMBED',
		DE =>  '-DDEBUGGING -DEMBED',
		M =>   '-DEMBED -DMULTIPLICITY',
		DM =>  '-DDEBUGGING -DEMBED -DMULTIPLICITY',
		);

    if ($libperl =~ /libperl(\w*)\Q$self->{LIB_EXT}/){
	$uc = uc($1);
    } else {
	$uc = ""; # avoid warning
    }
    $perltype = $map{$uc} ? $map{$uc} : "";

    if ($uc =~ /^D/) {
	$optdebug = "-g";
    }


    my($name);
    ( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ;
    if ($prog = $Config{$name}) {
	# Expand hints for this extension via the shell
	print "Processing $name hint:\n" if $Verbose;
	my(@o)=`cc=\"$cflags{cc}\"
	  ccflags=\"$cflags{ccflags}\"
	  optimize=\"$cflags{optimize}\"
	  perltype=\"$cflags{perltype}\"
	  optdebug=\"$cflags{optdebug}\"
	  eval '$prog'
	  echo cc=\$cc
	  echo ccflags=\$ccflags
	  echo optimize=\$optimize
	  echo perltype=\$perltype
	  echo optdebug=\$optdebug
	  `;
	foreach my $line (@o){
	    chomp $line;
	    if ($line =~ /(.*?)=\s*(.*)\s*$/){
		$cflags{$1} = $2;
		print "	$1 = $2\n" if $Verbose;
	    } else {
		print "Unrecognised result from hint: '$line'\n";
	    }
	}
    }

    if ($optdebug) {
	$cflags{optimize} = $optdebug;
    }

    for (qw(ccflags optimize perltype)) {
        $cflags{$_} ||= '';
	$cflags{$_} =~ s/^\s+//;
	$cflags{$_} =~ s/\s+/ /g;
	$cflags{$_} =~ s/\s+$//;
	$self->{uc $_} ||= $cflags{$_};
    }

    if ($self->{POLLUTE}) {
	$self->{CCFLAGS} .= ' -DPERL_POLLUTE ';
    }

    for my $x (@ccextraflags) {
      next unless exists $cflags{$x};
      $self->{CCFLAGS} .= $cflags{$x} =~ m!^\s! ? $cflags{$x} : ' ' . $cflags{$x};
    }

    my $pollute = '';
    if ($Config{usemymalloc} and not $Config{bincompat5005}
	and not $Config{ccflags} =~ /-DPERL_POLLUTE_MALLOC\b/
	and $self->{PERL_MALLOC_OK}) {
	$pollute = '$(PERL_MALLOC_DEF)';
    }

    return $self->{CFLAGS} = qq{
CCFLAGS = $self->{CCFLAGS}
OPTIMIZE = $self->{OPTIMIZE}
PERLTYPE = $self->{PERLTYPE}
MPOLLUTE = $pollute
};

}


=item const_cccmd (o)

Returns the full compiler call for C programs and stores the
definition in CONST_CCCMD.

=cut

sub const_cccmd {
    my($self,$libperl)=@_;
    return $self->{CONST_CCCMD} if $self->{CONST_CCCMD};
    return '' unless $self->needs_linking();
    return $self->{CONST_CCCMD} =
	q{CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \\
	$(CCFLAGS) $(OPTIMIZE) \\
	$(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \\
	$(XS_DEFINE_VERSION)};
}

=item const_config (o)

Sets SHELL if needed, then defines a couple of constants in the Makefile
that are imported from %Config.

=cut

sub const_config {
# --- Constants Sections ---

    my($self) = shift;
    my @m = $self->specify_shell(); # Usually returns empty string
    push @m, <<"END";

# These definitions are from config.sh (via $INC{'Config.pm'}).
# They may have been overridden via Makefile.PL or on the command line.
END

    my(%once_only);
    foreach my $key (@{$self->{CONFIG}}){
        # SITE*EXP macros are defined in &constants; avoid duplicates here
        next if $once_only{$key};
        push @m, uc($key) , ' = ' , $self->{uc $key}, "\n";
        $once_only{$key} = 1;
    }
    join('', @m);
}

=item const_loadlibs (o)

Defines EXTRALIBS, LDLOADLIBS, BSLOADLIBS, LD_RUN_PATH. See
L<ExtUtils::Liblist> for details.

=cut

sub const_loadlibs {
    my($self) = shift;
    return "" unless $self->needs_linking;
    my @m;
    push @m, qq{
# $self->{NAME} might depend on some other libraries:
# See ExtUtils::Liblist for details
#
};
    for my $tmp (qw/
         EXTRALIBS LDLOADLIBS BSLOADLIBS
         /) {
        next unless defined $self->{$tmp};
        push @m, "$tmp = $self->{$tmp}\n";
    }
    # don't set LD_RUN_PATH if empty
    for my $tmp (qw/
         LD_RUN_PATH
         /) {
        next unless $self->{$tmp};
        push @m, "$tmp = $self->{$tmp}\n";
    }
    return join "", @m;
}

=item constants (o)

  my $make_frag = $mm->constants;

Prints out macros for lots of constants.

=cut

sub constants {
    my($self) = @_;
    my @m = ();

    $self->{DFSEP} = '$(DIRFILESEP)';  # alias for internal use

    for my $macro (qw(

              AR_STATIC_ARGS DIRFILESEP DFSEP
              NAME NAME_SYM
              VERSION    VERSION_MACRO    VERSION_SYM DEFINE_VERSION
              XS_VERSION XS_VERSION_MACRO             XS_DEFINE_VERSION
              INST_ARCHLIB INST_SCRIPT INST_BIN INST_LIB
              INST_MAN1DIR INST_MAN3DIR
              MAN1EXT      MAN3EXT
              MAN1SECTION  MAN3SECTION
              INSTALLDIRS INSTALL_BASE DESTDIR PREFIX
              PERLPREFIX      SITEPREFIX      VENDORPREFIX
                   ),
                   (map { ("INSTALL".$_,
                          "DESTINSTALL".$_)
                        } $self->installvars),
                   qw(
              PERL_LIB
              PERL_ARCHLIB PERL_ARCHLIBDEP
              LIBPERL_A MYEXTLIB
              FIRST_MAKEFILE MAKEFILE_OLD MAKE_APERL_FILE
              PERLMAINCC PERL_SRC PERL_INC PERL_INCDEP
              PERL            FULLPERL          ABSPERL
              PERLRUN         FULLPERLRUN       ABSPERLRUN
              PERLRUNINST     FULLPERLRUNINST   ABSPERLRUNINST
              PERL_CORE
              PERM_DIR PERM_RW PERM_RWX

	      ) )
    {
	next unless defined $self->{$macro};

        # pathnames can have sharp signs in them; escape them so
        # make doesn't think it is a comment-start character.
        $self->{$macro} =~ s/#/\\#/g;
	$self->{$macro} = $self->quote_dep($self->{$macro})
	  if $ExtUtils::MakeMaker::macro_dep{$macro};
	push @m, "$macro = $self->{$macro}\n";
    }

    push @m, qq{
MAKEMAKER   = $self->{MAKEMAKER}
MM_VERSION  = $self->{MM_VERSION}
MM_REVISION = $self->{MM_REVISION}
};

    push @m, q{
# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
# DLBASE  = Basename part of dynamic library. May be just equal BASEEXT.
};

    for my $macro (qw/
              MAKE
	      FULLEXT BASEEXT PARENT_NAME DLBASE VERSION_FROM INC DEFINE OBJECT
	      LDFROM LINKTYPE BOOTDEP
	      /	)
    {
	next unless defined $self->{$macro};
	push @m, "$macro = $self->{$macro}\n";
    }

    push @m, "
# Handy lists of source code files:
XS_FILES = ".$self->wraplist(sort keys %{$self->{XS}})."
C_FILES  = ".$self->wraplist(sort @{$self->{C}})."
O_FILES  = ".$self->wraplist(sort @{$self->{O_FILES}})."
H_FILES  = ".$self->wraplist(sort @{$self->{H}})."
MAN1PODS = ".$self->wraplist(sort keys %{$self->{MAN1PODS}})."
MAN3PODS = ".$self->wraplist(sort keys %{$self->{MAN3PODS}})."
";

    push @m, q{
SDKROOT := $(shell xcrun --show-sdk-path)
PERL_SYSROOT = $(SDKROOT)
} if $Is{ApplCor} && $self->{'PERL_INC'} =~ m!^/System/Library/Perl/!;

    push @m, q{
# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_SYSROOT)$(PERL_INCDEP)$(DFSEP)config.h
} if $Is{ApplCor};

    push @m, q{
# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_INCDEP)$(DFSEP)config.h
} if -e $self->catfile( $self->{PERL_INC}, 'config.h' ) && !$Is{ApplCor};

    push @m, qq{
# Where to build things
INST_LIBDIR      = $self->{INST_LIBDIR}
INST_ARCHLIBDIR  = $self->{INST_ARCHLIBDIR}

INST_AUTODIR     = $self->{INST_AUTODIR}
INST_ARCHAUTODIR = $self->{INST_ARCHAUTODIR}

INST_STATIC      = $self->{INST_STATIC}
INST_DYNAMIC     = $self->{INST_DYNAMIC}
INST_BOOT        = $self->{INST_BOOT}
};

    push @m, qq{
# Extra linker info
EXPORT_LIST        = $self->{EXPORT_LIST}
PERL_ARCHIVE       = $self->{PERL_ARCHIVE}
PERL_ARCHIVEDEP    = $self->{PERL_ARCHIVEDEP}
PERL_ARCHIVE_AFTER = $self->{PERL_ARCHIVE_AFTER}
};

    push @m, "

TO_INST_PM = ".$self->wraplist(map $self->quote_dep($_), sort keys %{$self->{PM}})."\n";

    join('',@m);
}


=item depend (o)

Same as macro for the depend attribute.

=cut

sub depend {
    my($self,%attribs) = @_;
    my(@m,$key,$val);
    for my $key (sort keys %attribs){
	my $val = $attribs{$key};
	next unless defined $key and defined $val;
	push @m, "$key : $val\n";
    }
    join "", @m;
}


=item init_DEST

  $mm->init_DEST

Defines the DESTDIR and DEST* variables paralleling the INSTALL*.

=cut

sub init_DEST {
    my $self = shift;

    # Initialize DESTDIR
    $self->{DESTDIR} ||= '';

    # Make DEST variables.
    foreach my $var ($self->installvars) {
        my $destvar = 'DESTINSTALL'.$var;
        $self->{$destvar} ||= '$(DESTDIR)$(INSTALL'.$var.')';
    }
}


=item init_dist

  $mm->init_dist;

Defines a lot of macros for distribution support.

  macro         description                     default

  TAR           tar command to use              tar
  TARFLAGS      flags to pass to TAR            cvf

  ZIP           zip command to use              zip
  ZIPFLAGS      flags to pass to ZIP            -r

  COMPRESS      compression command to          gzip --best
                use for tarfiles
  SUFFIX        suffix to put on                .gz
                compressed files

  SHAR          shar command to use             shar

  PREOP         extra commands to run before
                making the archive
  POSTOP        extra commands to run after
                making the archive

  TO_UNIX       a command to convert linefeeds
                to Unix style in your archive

  CI            command to checkin your         ci -u
                sources to version control
  RCS_LABEL     command to label your sources   rcs -Nv$(VERSION_SYM): -q
                just after CI is run

  DIST_CP       $how argument to manicopy()     best
                when the distdir is created

  DIST_DEFAULT  default target to use to        tardist
                create a distribution

  DISTVNAME     name of the resulting archive   $(DISTNAME)-$(VERSION)
                (minus suffixes)

=cut

sub init_dist {
    my $self = shift;

    $self->{TAR}      ||= 'tar';
    $self->{TARFLAGS} ||= 'cvf';
    $self->{ZIP}      ||= 'zip';
    $self->{ZIPFLAGS} ||= '-r';
    $self->{COMPRESS} ||= 'gzip --best';
    $self->{SUFFIX}   ||= '.gz';
    $self->{SHAR}     ||= 'shar';
    $self->{PREOP}    ||= '$(NOECHO) $(NOOP)'; # eg update MANIFEST
    $self->{POSTOP}   ||= '$(NOECHO) $(NOOP)'; # eg remove the distdir
    $self->{TO_UNIX}  ||= '$(NOECHO) $(NOOP)';

    $self->{CI}       ||= 'ci -u';
    $self->{RCS_LABEL}||= 'rcs -Nv$(VERSION_SYM): -q';
    $self->{DIST_CP}  ||= 'best';
    $self->{DIST_DEFAULT} ||= 'tardist';

    ($self->{DISTNAME} = $self->{NAME}) =~ s{::}{-}g unless $self->{DISTNAME};
    $self->{DISTVNAME} ||= $self->{DISTNAME}.'-'.$self->{VERSION};
}

=item dist (o)

  my $dist_macros = $mm->dist(%overrides);

Generates a make fragment defining all the macros initialized in
init_dist.

%overrides can be used to override any of the above.

=cut

sub dist {
    my($self, %attribs) = @_;

    my $make = '';
    if ( $attribs{SUFFIX} && $attribs{SUFFIX} !~ m!^\.! ) {
      $attribs{SUFFIX} = '.' . $attribs{SUFFIX};
    }
    foreach my $key (qw(
            TAR TARFLAGS ZIP ZIPFLAGS COMPRESS SUFFIX SHAR
            PREOP POSTOP TO_UNIX
            CI RCS_LABEL DIST_CP DIST_DEFAULT
            DISTNAME DISTVNAME
           ))
    {
        my $value = $attribs{$key} || $self->{$key};
        $make .= "$key = $value\n";
    }

    return $make;
}

=item dist_basics (o)

Defines the targets distclean, distcheck, skipcheck, manifest, veryclean.

=cut

sub dist_basics {
    my($self) = shift;

    return <<'MAKE_FRAG';
distclean :: realclean distcheck
	$(NOECHO) $(NOOP)

distcheck :
	$(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck

skipcheck :
	$(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck

manifest :
	$(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest

veryclean : realclean
	$(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old

MAKE_FRAG

}

=item dist_ci (o)

Defines a check in target for RCS.

=cut

sub dist_ci {
    my($self) = shift;
    return sprintf "ci :\n\t%s\n", $self->oneliner(<<'EOF', [qw(-MExtUtils::Manifest=maniread)]);
@all = sort keys %{ maniread() };
print(qq{Executing $(CI) @all\n});
system(qq{$(CI) @all}) == 0 or die $!;
print(qq{Executing $(RCS_LABEL) ...\n});
system(qq{$(RCS_LABEL) @all}) == 0 or die $!;
EOF
}

=item dist_core (o)

  my $dist_make_fragment = $MM->dist_core;

Puts the targets necessary for 'make dist' together into one make
fragment.

=cut

sub dist_core {
    my($self) = shift;

    my $make_frag = '';
    foreach my $target (qw(dist tardist uutardist tarfile zipdist zipfile
                           shdist))
    {
        my $method = $target.'_target';
        $make_frag .= "\n";
        $make_frag .= $self->$method();
    }

    return $make_frag;
}


=item B<dist_target>

  my $make_frag = $MM->dist_target;

Returns the 'dist' target to make an archive for distribution.  This
target simply checks to make sure the Makefile is up-to-date and
depends on $(DIST_DEFAULT).

=cut

sub dist_target {
    my($self) = shift;

    my $date_check = $self->oneliner(<<'CODE', ['-l']);
print 'Warning: Makefile possibly out of date with $(VERSION_FROM)'
    if -e '$(VERSION_FROM)' and -M '$(VERSION_FROM)' < -M '$(FIRST_MAKEFILE)';
CODE

    return sprintf <<'MAKE_FRAG', $date_check;
dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE)
	$(NOECHO) %s
MAKE_FRAG
}

=item B<tardist_target>

  my $make_frag = $MM->tardist_target;

Returns the 'tardist' target which is simply so 'make tardist' works.
The real work is done by the dynamically named tardistfile_target()
method, tardist should have that as a dependency.

=cut

sub tardist_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
tardist : $(DISTVNAME).tar$(SUFFIX)
	$(NOECHO) $(NOOP)
MAKE_FRAG
}

=item B<zipdist_target>

  my $make_frag = $MM->zipdist_target;

Returns the 'zipdist' target which is simply so 'make zipdist' works.
The real work is done by the dynamically named zipdistfile_target()
method, zipdist should have that as a dependency.

=cut

sub zipdist_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
zipdist : $(DISTVNAME).zip
	$(NOECHO) $(NOOP)
MAKE_FRAG
}

=item B<tarfile_target>

  my $make_frag = $MM->tarfile_target;

The name of this target is the name of the tarball generated by
tardist.  This target does the actual work of turning the distdir into
a tarball.

=cut

sub tarfile_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
$(DISTVNAME).tar$(SUFFIX) : distdir
	$(PREOP)
	$(TO_UNIX)
	$(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME)
	$(RM_RF) $(DISTVNAME)
	$(COMPRESS) $(DISTVNAME).tar
	$(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)'
	$(POSTOP)
MAKE_FRAG
}

=item zipfile_target

  my $make_frag = $MM->zipfile_target;

The name of this target is the name of the zip file generated by
zipdist.  This target does the actual work of turning the distdir into
a zip file.

=cut

sub zipfile_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
$(DISTVNAME).zip : distdir
	$(PREOP)
	$(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME)
	$(RM_RF) $(DISTVNAME)
	$(NOECHO) $(ECHO) 'Created $(DISTVNAME).zip'
	$(POSTOP)
MAKE_FRAG
}

=item uutardist_target

  my $make_frag = $MM->uutardist_target;

Converts the tarfile into a uuencoded file

=cut

sub uutardist_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
uutardist : $(DISTVNAME).tar$(SUFFIX)
	uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu
	$(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)_uu'
MAKE_FRAG
}


=item shdist_target

  my $make_frag = $MM->shdist_target;

Converts the distdir into a shell archive.

=cut

sub shdist_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
shdist : distdir
	$(PREOP)
	$(SHAR) $(DISTVNAME) > $(DISTVNAME).shar
	$(RM_RF) $(DISTVNAME)
	$(NOECHO) $(ECHO) 'Created $(DISTVNAME).shar'
	$(POSTOP)
MAKE_FRAG
}


=item dlsyms (o)

Used by some OS' to define DL_FUNCS and DL_VARS and write the *.exp files.

Normally just returns an empty string.

=cut

sub dlsyms {
    return '';
}


=item dynamic_bs (o)

Defines targets for bootstrap files.

=cut

sub dynamic_bs {
    my($self, %attribs) = @_;
    return "\nBOOTSTRAP =\n" unless $self->has_link_code();
    my @exts;
    if ($self->{XSMULTI}) {
	@exts = $self->_xs_list_basenames;
    } else {
	@exts = '$(BASEEXT)';
    }
    return join "\n",
        "BOOTSTRAP = @{[map { qq{$_.bs} } @exts]}\n",
        map { $self->_xs_make_bs($_) } @exts;
}

sub _xs_make_bs {
    my ($self, $basename) = @_;
    my ($v, $d, $f) = File::Spec->splitpath($basename);
    my @d = File::Spec->splitdir($d);
    shift @d if $self->{XSMULTI} and $d[0] eq 'lib';
    my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
    $instdir = '$(INST_ARCHAUTODIR)' if $basename eq '$(BASEEXT)';
    my $instfile = $self->catfile($instdir, "$f.bs");
    my $exists = "$instdir\$(DFSEP).exists"; # match blibdirs_target
    #                                 1          2          3
    return _sprintf562 <<'MAKE_FRAG', $basename, $instfile, $exists;
# As Mkbootstrap might not write a file (if none is required)
# we use touch to prevent make continually trying to remake it.
# The DynaLoader only reads a non-empty file.
%1$s.bs : $(FIRST_MAKEFILE) $(BOOTDEP)
	$(NOECHO) $(ECHO) "Running Mkbootstrap for %1$s ($(BSLOADLIBS))"
	$(NOECHO) $(PERLRUN) \
		"-MExtUtils::Mkbootstrap" \
		-e "Mkbootstrap('%1$s','$(BSLOADLIBS)');"
	$(NOECHO) $(TOUCH) "%1$s.bs"
	$(CHMOD) $(PERM_RW) "%1$s.bs"

%2$s : %1$s.bs %3$s
	$(NOECHO) $(RM_RF) %2$s
	- $(CP_NONEMPTY) %1$s.bs %2$s $(PERM_RW)
MAKE_FRAG
}

=item dynamic_lib (o)

Defines how to produce the *.so (or equivalent) files.

=cut

sub dynamic_lib {
    my($self, %attribs) = @_;
    return '' unless $self->needs_linking(); #might be because of a subdir
    return '' unless $self->has_link_code;
    my @m = $self->xs_dynamic_lib_macros(\%attribs);
    my @libs;
    my $dlsyms_ext = eval { $self->xs_dlsyms_ext };
    if ($self->{XSMULTI}) {
        my @exts = $self->_xs_list_basenames;
        for my $ext (@exts) {
            my ($v, $d, $f) = File::Spec->splitpath($ext);
            my @d = File::Spec->splitdir($d);
            shift @d if $d[0] eq 'lib';
            pop @d if $d[$#d] eq '';
            my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);

            # Dynamic library names may need special handling.
            eval { require DynaLoader };
            if (defined &DynaLoader::mod2fname) {
                $f = &DynaLoader::mod2fname([@d, $f]);
            }

            my $instfile = $self->catfile($instdir, "$f.\$(DLEXT)");
            my $objfile = $self->_xsbuild_value('xs', $ext, 'OBJECT');
            $objfile = "$ext\$(OBJ_EXT)" unless defined $objfile;
            my $ldfrom = $self->_xsbuild_value('xs', $ext, 'LDFROM');
            $ldfrom = $objfile unless defined $ldfrom;
            my $exportlist = "$ext.def";
            my @libchunk = ($objfile, $instfile, $instdir, $ldfrom, $exportlist);
            push @libchunk, $dlsyms_ext ? $ext.$dlsyms_ext : undef;
            push @libs, \@libchunk;
        }
    } else {
        my @libchunk = qw($(OBJECT) $(INST_DYNAMIC) $(INST_ARCHAUTODIR) $(LDFROM) $(EXPORT_LIST));
        push @libchunk, $dlsyms_ext ? '$(BASEEXT)'.$dlsyms_ext : undef;
        @libs = (\@libchunk);
    }
    push @m, map { $self->xs_make_dynamic_lib(\%attribs, @$_); } @libs;

    return join("\n",@m);
}

=item xs_dynamic_lib_macros

Defines the macros for the C<dynamic_lib> section.

=cut

sub xs_dynamic_lib_macros {
    my ($self, $attribs) = @_;
    my $otherldflags = $attribs->{OTHERLDFLAGS} || "";
    my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
    my $armaybe = $self->_xs_armaybe($attribs);
    my $ld_opt = $Is{OS2} ? '$(OPTIMIZE) ' : ''; # Useful on other systems too?
    my $ld_fix = $Is{OS2} ? '|| ( $(RM_F) $@ && sh -c false )' : '';
    sprintf <<'EOF', $armaybe, $ld_opt.$otherldflags, $inst_dynamic_dep, $ld_fix;
# This section creates the dynamically loadable objects from relevant
# objects and possibly $(MYEXTLIB).
ARMAYBE = %s
OTHERLDFLAGS = %s
INST_DYNAMIC_DEP = %s
INST_DYNAMIC_FIX = %s
EOF
}

sub _xs_armaybe {
    my ($self, $attribs) = @_;
    my $armaybe = $attribs->{ARMAYBE} || $self->{ARMAYBE} || ":";
    $armaybe = 'ar' if ($Is{OSF} and $armaybe eq ':');
    $armaybe;
}

=item xs_make_dynamic_lib

Defines the recipes for the C<dynamic_lib> section.

=cut

sub xs_make_dynamic_lib {
    my ($self, $attribs, $object, $to, $todir, $ldfrom, $exportlist, $dlsyms) = @_;
    $exportlist = '' if $exportlist ne '$(EXPORT_LIST)';
    my $armaybe = $self->_xs_armaybe($attribs);
    my @m = sprintf '%s : %s $(MYEXTLIB) %s$(DFSEP).exists %s $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP) %s'."\n", $to, $object, $todir, $exportlist, ($dlsyms || '');
    my $dlsyms_arg = $self->xs_dlsyms_arg($dlsyms);
    if ($armaybe ne ':'){
        $ldfrom = 'tmp$(LIB_EXT)';
        push(@m,"	\$(ARMAYBE) cr $ldfrom $object\n");
        push(@m,"	\$(RANLIB) $ldfrom\n");
    }
    $ldfrom = "-all $ldfrom -none" if $Is{OSF};

    my $ldrun = '';
    # The IRIX linker doesn't use LD_RUN_PATH
    if ( $self->{LD_RUN_PATH} ) {
        if ( $Is{IRIX} ) {
            $ldrun = qq{-rpath "$self->{LD_RUN_PATH}"};
        }
        elsif ( $^O eq 'darwin' ) {
            # both clang and gcc support -Wl,-rpath, but only clang supports
            # -rpath so by using -Wl,-rpath we avoid having to check for the
            # type of compiler
            $ldrun = qq{-Wl,-rpath,"$self->{LD_RUN_PATH}"};
        }
    }

    # For example in AIX the shared objects/libraries from previous builds
    # linger quite a while in the shared dynalinker cache even when nobody
    # is using them.  This is painful if one for instance tries to restart
    # a failed build because the link command will fail unnecessarily 'cos
    # the shared object/library is 'busy'.
    push(@m,"	\$(RM_F) \$\@\n");

    my $libs = '$(LDLOADLIBS)';
    if (($Is{NetBSD} || $Is{Interix} || $Is{Android}) && $Config{'useshrplib'} eq 'true') {
        # Use nothing on static perl platforms, and to the flags needed
        # to link against the shared libperl library on shared perl
        # platforms.  We peek at lddlflags to see if we need -Wl,-R
        # or -R to add paths to the run-time library search path.
        if ($Config{'lddlflags'} =~ /-Wl,-R/) {
            $libs .= ' "-L$(PERL_INC)" "-Wl,-R$(INSTALLARCHLIB)/CORE" "-Wl,-R$(PERL_ARCHLIB)/CORE" -lperl';
        } elsif ($Config{'lddlflags'} =~ /-R/) {
            $libs .= ' "-L$(PERL_INC)" "-R$(INSTALLARCHLIB)/CORE" "-R$(PERL_ARCHLIB)/CORE" -lperl';
        } elsif ( $Is{Android} ) {
            # The Android linker will not recognize symbols from
            # libperl unless the module explicitly depends on it.
            $libs .= ' "-L$(PERL_INC)" -lperl';
        }
    }

    my $ld_run_path_shell = "";
    if ($self->{LD_RUN_PATH} ne "") {
        $ld_run_path_shell = 'LD_RUN_PATH="$(LD_RUN_PATH)" ';
    }

    push @m, sprintf <<'MAKE', $ld_run_path_shell, $ldrun, $dlsyms_arg, $ldfrom, $self->xs_obj_opt('$@'), $libs, $exportlist;
	%s$(LD) %s $(LDDLFLAGS) %s %s $(OTHERLDFLAGS) %s $(MYEXTLIB) \
	  $(PERL_ARCHIVE) %s $(PERL_ARCHIVE_AFTER) %s \
	  $(INST_DYNAMIC_FIX)
	$(CHMOD) $(PERM_RWX) $@
MAKE
    join '', @m;
}

=item exescan

Deprecated method. Use libscan instead.

=cut

sub exescan {
    my($self,$path) = @_;
    $path;
}

=item extliblist

Called by init_others, and calls ext ExtUtils::Liblist. See
L<ExtUtils::Liblist> for details.

=cut

sub extliblist {
    my($self,$libs) = @_;
    require ExtUtils::Liblist;
    $self->ext($libs, $Verbose);
}

=item find_perl

Finds the executables PERL and FULLPERL

=cut

sub find_perl {
    my($self, $ver, $names, $dirs, $trace) = @_;
    if ($trace >= 2){
        print "Looking for perl $ver by these names:
@$names
in these dirs:
@$dirs
";
    }

    my $stderr_duped = 0;
    local *STDERR_COPY;

    unless ($Is{BSD}) {
        # >& and lexical filehandles together give 5.6.2 indigestion
        if( open(STDERR_COPY, '>&STDERR') ) {  ## no critic
            $stderr_duped = 1;
        }
        else {
            warn <<WARNING;
find_perl() can't dup STDERR: $!
You might see some garbage while we search for Perl
WARNING
        }
    }

    foreach my $name (@$names){
        my ($abs, $use_dir);
        if ($self->file_name_is_absolute($name)) {     # /foo/bar
            $abs = $name;
        } elsif ($self->canonpath($name) eq
                 $self->canonpath(basename($name))) {  # foo
            $use_dir = 1;
        } else {                                            # foo/bar
            $abs = $self->catfile($Curdir, $name);
        }
        foreach my $dir ($use_dir ? @$dirs : 1){
            next unless defined $dir; # $self->{PERL_SRC} may be undefined

            $abs = $self->catfile($dir, $name)
                if $use_dir;

            print "Checking $abs\n" if ($trace >= 2);
            next unless $self->maybe_command($abs);
            print "Executing $abs\n" if ($trace >= 2);

            my $val;
            my $version_check = qq{"$abs" -le "require $ver; print qq{VER_OK}"};

            # To avoid using the unportable 2>&1 to suppress STDERR,
            # we close it before running the command.
            # However, thanks to a thread library bug in many BSDs
            # ( http://www.freebsd.org/cgi/query-pr.cgi?pr=51535 )
            # we cannot use the fancier more portable way in here
            # but instead need to use the traditional 2>&1 construct.
            if ($Is{BSD}) {
                $val = `$version_check 2>&1`;
            } else {
                close STDERR if $stderr_duped;
                $val = `$version_check`;

                # 5.6.2's 3-arg open doesn't work with >&
                open STDERR, ">&STDERR_COPY"  ## no critic
                        if $stderr_duped;
            }

            if ($val =~ /^VER_OK/m) {
                print "Using PERL=$abs\n" if $trace;
                return $abs;
            } elsif ($trace >= 2) {
                print "Result: '$val' ".($? >> 8)."\n";
            }
        }
    }
    print "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n";
    0; # false and not empty
}


=item fixin

  $mm->fixin(@files);

Inserts the sharpbang or equivalent magic number to a set of @files.

=cut

sub fixin {    # stolen from the pink Camel book, more or less
    my ( $self, @files ) = @_;

    for my $file (@files) {
        my $file_new = "$file.new";
        my $file_bak = "$file.bak";

        open( my $fixin, '<', $file ) or croak "Can't process '$file': $!";
        local $/ = "\n";
        chomp( my $line = <$fixin> );
        next unless $line =~ s/^\s*\#!\s*//;    # Not a shebang file.

        my $shb = $self->_fixin_replace_shebang( $file, $line );
        next unless defined $shb;

        open( my $fixout, ">", "$file_new" ) or do {
            warn "Can't create new $file: $!\n";
            next;
        };

        # Print out the new #! line (or equivalent).
        local $\;
        local $/;
        print $fixout $shb, <$fixin>;
        close $fixin;
        close $fixout;

        chmod 0666, $file_bak;
        unlink $file_bak;
        unless ( _rename( $file, $file_bak ) ) {
            warn "Can't rename $file to $file_bak: $!";
            next;
        }
        unless ( _rename( $file_new, $file ) ) {
            warn "Can't rename $file_new to $file: $!";
            unless ( _rename( $file_bak, $file ) ) {
                warn "Can't rename $file_bak back to $file either: $!";
                warn "Leaving $file renamed as $file_bak\n";
            }
            next;
        }
        unlink $file_bak;
    }
    continue {
        system("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
    }
}


sub _rename {
    my($old, $new) = @_;

    foreach my $file ($old, $new) {
        if( $Is{VMS} and basename($file) !~ /\./ ) {
            # rename() in 5.8.0 on VMS will not rename a file if it
            # does not contain a dot yet it returns success.
            $file = "$file.";
        }
    }

    return rename($old, $new);
}

sub _fixin_replace_shebang {
    my ( $self, $file, $line ) = @_;

    # Now figure out the interpreter name.
    my ( $origcmd, $arg ) = split ' ', $line, 2;
    (my $cmd = $origcmd) =~ s!^.*/!!;

    # Now look (in reverse) for interpreter in absolute PATH (unless perl).
    my $interpreter;
    if ( defined $ENV{PERL_MM_SHEBANG} && $ENV{PERL_MM_SHEBANG} eq "relocatable" ) {
        $interpreter = "/usr/bin/env perl";
    }
    elsif ( $cmd =~ m{^perl(?:\z|[^a-z])} ) {
        if ( $Config{startperl} =~ m,^\#!.*/perl, ) {
            $interpreter = $Config{startperl};
            $interpreter =~ s,^\#!,,;
        }
        else {
            $interpreter = $Config{perlpath};
        }
    }
    else {
        my (@absdirs)
            = reverse grep { $self->file_name_is_absolute($_) } $self->path;
        $interpreter = '';

        foreach my $dir (@absdirs) {
            my $maybefile = $self->catfile($dir,$cmd);
            if ( $self->maybe_command($maybefile) ) {
                warn "Ignoring $interpreter in $file\n"
                    if $Verbose && $interpreter;
                $interpreter = $maybefile;
            }
        }

        # If the shebang is absolute and exists in PATH, but was not
        # the first one found, leave it alone if it's actually the
        # same file as first one.  This avoids packages built on
        # merged-/usr systems with /usr/bin before /bin in the path
        # breaking when installed on systems without merged /usr
        if ($origcmd ne $interpreter and $self->file_name_is_absolute($origcmd)) {
            my $origdir = dirname($origcmd);
            if ($self->maybe_command($origcmd) && grep { $_ eq $origdir } @absdirs) {
                my ($odev, $oino) = stat $origcmd;
                my ($idev, $iino) = stat $interpreter;
                if ($odev == $idev && $oino eq $iino) {
                    warn "$origcmd is the same as $interpreter, leaving alone"
                        if $Verbose;
                    $interpreter = $origcmd;
                }
            }
        }
    }

    # Figure out how to invoke interpreter on this machine.

    my ($does_shbang) = $Config{'sharpbang'} =~ /^\s*\#\!/;
    my ($shb) = "";
    if ($interpreter) {
        print "Changing sharpbang in $file to $interpreter"
            if $Verbose;
         # this is probably value-free on DOSISH platforms
        if ($does_shbang) {
            $shb .= "$Config{'sharpbang'}$interpreter";
            $shb .= ' ' . $arg if defined $arg;
            $shb .= "\n";
        }
    }
    else {
        warn "Can't find $cmd in PATH, $file unchanged"
            if $Verbose;
        return;
    }
    return $shb
}

=item force (o)

Writes an empty FORCE: target.

=cut

sub force {
    my($self) = shift;
    '# Phony target to force checking subdirectories.
FORCE :
	$(NOECHO) $(NOOP)
';
}

=item guess_name

Guess the name of this package by examining the working directory's
name. MakeMaker calls this only if the developer has not supplied a
NAME attribute.

=cut

# ';

sub guess_name {
    my($self) = @_;
    use Cwd 'cwd';
    my $name = basename(cwd());
    $name =~ s|[\-_][\d\.\-]+\z||;  # this is new with MM 5.00, we
                                    # strip minus or underline
                                    # followed by a float or some such
    print "Warning: Guessing NAME [$name] from current directory name.\n";
    $name;
}

=item has_link_code

Returns true if C, XS, MYEXTLIB or similar objects exist within this
object that need a compiler. Does not descend into subdirectories as
needs_linking() does.

=cut

sub has_link_code {
    my($self) = shift;
    return $self->{HAS_LINK_CODE} if defined $self->{HAS_LINK_CODE};
    if ($self->{OBJECT} or @{$self->{C} || []} or $self->{MYEXTLIB}){
	$self->{HAS_LINK_CODE} = 1;
	return 1;
    }
    return $self->{HAS_LINK_CODE} = 0;
}


=item init_dirscan

Scans the directory structure and initializes DIR, XS, XS_FILES,
C, C_FILES, O_FILES, H, H_FILES, PL_FILES, EXE_FILES.

Called by init_main.

=cut

sub init_dirscan {	# --- File and Directory Lists (.xs .pm .pod etc)
    my($self) = @_;
    my(%dir, %xs, %c, %o, %h, %pl_files, %pm);

    my %ignore = map {( $_ => 1 )} qw(Makefile.PL Build.PL test.pl t);

    # ignore the distdir
    $Is{VMS} ? $ignore{"$self->{DISTVNAME}.dir"} = 1
            : $ignore{$self->{DISTVNAME}} = 1;

    my $distprefix = $Is{VMS} ? qr/^\Q$self->{DISTNAME}\E-v?[\d\.]+\.dir$/i
                              : qr/^\Q$self->{DISTNAME}\E-v?[\d\.]+$/;

    @ignore{map lc, keys %ignore} = values %ignore if $Is{VMS};

    if ( defined $self->{XS} and !defined $self->{C} ) {
	my @c_files = grep { m/\.c(pp|xx)?\z/i } values %{$self->{XS}};
	my @o_files = grep { m/(?:.(?:o(?:bj)?)|\$\(OBJ_EXT\))\z/i } values %{$self->{XS}};
	%c = map { $_ => 1 } @c_files;
	%o = map { $_ => 1 } @o_files;
    }

    foreach my $name ($self->lsdir($Curdir)){
	next if $name =~ /\#/;
	next if $name =~ $distprefix && -d $name;
	$name = lc($name) if $Is{VMS};
	next if $name eq $Curdir or $name eq $Updir or $ignore{$name};
	next unless $self->libscan($name);
	if (-d $name){
	    next if -l $name; # We do not support symlinks at all
            next if $self->{NORECURS};
	    $dir{$name} = $name if (-f $self->catfile($name,"Makefile.PL"));
	} elsif ($name =~ /\.xs\z/){
	    my($c); ($c = $name) =~ s/\.xs\z/.c/;
	    $xs{$name} = $c;
	    $c{$c} = 1;
	} elsif ($name =~ /\.c(pp|xx|c)?\z/i){  # .c .C .cpp .cxx .cc
	    $c{$name} = 1
		unless $name =~ m/perlmain\.c/; # See MAP_TARGET
	} elsif ($name =~ /\.h\z/i){
	    $h{$name} = 1;
	} elsif ($name =~ /\.PL\z/) {
	    ($pl_files{$name} = $name) =~ s/\.PL\z// ;
	} elsif (($Is{VMS} || $Is{Dos}) && $name =~ /[._]pl$/i) {
	    # case-insensitive filesystem, one dot per name, so foo.h.PL
	    # under Unix appears as foo.h_pl under VMS or fooh.pl on Dos
	    local($/); open(my $pl, '<', $name); my $txt = <$pl>; close $pl;
	    if ($txt =~ /Extracting \S+ \(with variable substitutions/) {
		($pl_files{$name} = $name) =~ s/[._]pl\z//i ;
	    }
	    else {
                $pm{$name} = $self->catfile($self->{INST_LIBDIR},$name);
            }
	} elsif ($name =~ /\.(p[ml]|pod)\z/){
	    $pm{$name} = $self->catfile($self->{INST_LIBDIR},$name);
	}
    }

    $self->{PL_FILES}   ||= \%pl_files;
    $self->{DIR}        ||= [sort keys %dir];
    $self->{XS}         ||= \%xs;
    $self->{C}          ||= [sort keys %c];
    $self->{H}          ||= [sort keys %h];
    $self->{PM}         ||= \%pm;

    my @o_files = @{$self->{C}};
    %o = (%o, map { $_ => 1 } grep s/\.c(pp|xx|c)?\z/$self->{OBJ_EXT}/i, @o_files);
    $self->{O_FILES} = [sort keys %o];
}


=item init_MANPODS

Determines if man pages should be generated and initializes MAN1PODS
and MAN3PODS as appropriate.

=cut

sub init_MANPODS {
    my $self = shift;

    # Set up names of manual pages to generate from pods
    foreach my $man (qw(MAN1 MAN3)) {
        if ( $self->{"${man}PODS"}
             or $self->{"INSTALL${man}DIR"} =~ /^(none|\s*)$/
        ) {
            $self->{"${man}PODS"} ||= {};
        }
        else {
            my $init_method = "init_${man}PODS";
            $self->$init_method();
        }
    }

    # logic similar to picking man${num}ext in perl's Configure script
    foreach my $num (1,3) {
        my $installdirs = uc $self->{INSTALLDIRS};
        $installdirs = '' if $installdirs eq 'PERL';
        my @mandirs = File::Spec->splitdir( $self->_expand_macros(
            $self->{ "INSTALL${installdirs}MAN${num}DIR" } ) );
        my $mandir = pop @mandirs;
        my $section = $num;

        foreach ($num, "${num}p", "${num}pm", qw< l n o C L >, "L$num") {
            if ( $mandir =~ /^(?:man|cat)$_$/ ) {
                $section = $_;
                last;
            }
        }

        $self->{"MAN${num}SECTION"} = $section;
    }
}


sub _has_pod {
    my($self, $file) = @_;

    my($ispod)=0;
    if (open( my $fh, '<', $file )) {
        while (<$fh>) {
            if (/^=(?:head\d+|item|pod)\b/) {
                $ispod=1;
                last;
            }
        }
        close $fh;
    } else {
        # If it doesn't exist yet, we assume, it has pods in it
        $ispod = 1;
    }

    return $ispod;
}


=item init_MAN1PODS

Initializes MAN1PODS from the list of EXE_FILES.

=cut

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

    if ( exists $self->{EXE_FILES} ) {
	foreach my $name (@{$self->{EXE_FILES}}) {
	    next unless $self->_has_pod($name);

	    $self->{MAN1PODS}->{$name} =
		$self->catfile("\$(INST_MAN1DIR)",
			       basename($name).".\$(MAN1EXT)");
	}
    }
}


=item init_MAN3PODS

Initializes MAN3PODS from the list of PM files.

=cut

sub init_MAN3PODS {
    my $self = shift;

    my %manifypods = (); # we collect the keys first, i.e. the files
                         # we have to convert to pod

    foreach my $name (keys %{$self->{PM}}) {
	if ($name =~ /\.pod\z/ ) {
	    $manifypods{$name} = $self->{PM}{$name};
	} elsif ($name =~ /\.p[ml]\z/ ) {
	    if( $self->_has_pod($name) ) {
		$manifypods{$name} = $self->{PM}{$name};
	    }
	}
    }

    my $parentlibs_re = join '|', @{$self->{PMLIBPARENTDIRS}};

    # Remove "Configure.pm" and similar, if it's not the only pod listed
    # To force inclusion, just name it "Configure.pod", or override
    # MAN3PODS
    foreach my $name (keys %manifypods) {
	if (
            ($self->{PERL_CORE} and $name =~ /(config|setup).*\.pm/is) or
            ( $name =~ m/^README\.pod$/i ) # don't manify top-level README.pod
        ) {
	    delete $manifypods{$name};
	    next;
	}
	my($manpagename) = $name;
	$manpagename =~ s/\.p(od|m|l)\z//;
	# everything below lib is ok
	unless($manpagename =~ s!^\W*($parentlibs_re)\W+!!s) {
	    $manpagename = $self->catfile(
	        split(/::/,$self->{PARENT_NAME}),$manpagename
	    );
	}
	$manpagename = $self->replace_manpage_separator($manpagename);
	$self->{MAN3PODS}->{$name} =
	    $self->catfile("\$(INST_MAN3DIR)", "$manpagename.\$(MAN3EXT)");
    }
}


=item init_PM

Initializes PMLIBDIRS and PM from PMLIBDIRS.

=cut

sub init_PM {
    my $self = shift;

    # Some larger extensions often wish to install a number of *.pm/pl
    # files into the library in various locations.

    # The attribute PMLIBDIRS holds an array reference which lists
    # subdirectories which we should search for library files to
    # install. PMLIBDIRS defaults to [ 'lib', $self->{BASEEXT} ].  We
    # recursively search through the named directories (skipping any
    # which don't exist or contain Makefile.PL files).

    # For each *.pm or *.pl file found $self->libscan() is called with
    # the default installation path in $_[1]. The return value of
    # libscan defines the actual installation location.  The default
    # libscan function simply returns the path.  The file is skipped
    # if libscan returns false.

    # The default installation location passed to libscan in $_[1] is:
    #
    #  ./*.pm		=> $(INST_LIBDIR)/*.pm
    #  ./xyz/...	=> $(INST_LIBDIR)/xyz/...
    #  ./lib/...	=> $(INST_LIB)/...
    #
    # In this way the 'lib' directory is seen as the root of the actual
    # perl library whereas the others are relative to INST_LIBDIR
    # (which includes PARENT_NAME). This is a subtle distinction but one
    # that's important for nested modules.

    unless( $self->{PMLIBDIRS} ) {
        if( $Is{VMS} ) {
            # Avoid logical name vs directory collisions
            $self->{PMLIBDIRS} = ['./lib', "./$self->{BASEEXT}"];
        }
        else {
            $self->{PMLIBDIRS} = ['lib', $self->{BASEEXT}];
        }
    }

    #only existing directories that aren't in $dir are allowed

    # Avoid $_ wherever possible:
    # @{$self->{PMLIBDIRS}} = grep -d && !$dir{$_}, @{$self->{PMLIBDIRS}};
    my (@pmlibdirs) = @{$self->{PMLIBDIRS}};
    @{$self->{PMLIBDIRS}} = ();
    my %dir = map { ($_ => $_) } @{$self->{DIR}};
    foreach my $pmlibdir (@pmlibdirs) {
	-d $pmlibdir && !$dir{$pmlibdir} && push @{$self->{PMLIBDIRS}}, $pmlibdir;
    }

    unless( $self->{PMLIBPARENTDIRS} ) {
	@{$self->{PMLIBPARENTDIRS}} = ('lib');
    }

    return if $self->{PM} and $self->{ARGS}{PM};

    if (@{$self->{PMLIBDIRS}}){
	print "Searching PMLIBDIRS: @{$self->{PMLIBDIRS}}\n"
	    if ($Verbose >= 2);
	require File::Find;
        File::Find::find(sub {
            if (-d $_){
                unless ($self->libscan($_)){
                    $File::Find::prune = 1;
                }
                return;
            }
            return if /\#/;
            return if /~$/;             # emacs temp files
            return if /,v$/;            # RCS files
            return if m{\.swp$};        # vim swap files

	    my $path   = $File::Find::name;
            my $prefix = $self->{INST_LIBDIR};
            my $striplibpath;

	    my $parentlibs_re = join '|', @{$self->{PMLIBPARENTDIRS}};
	    $prefix =  $self->{INST_LIB}
                if ($striplibpath = $path) =~ s{^(\W*)($parentlibs_re)\W}
	                                       {$1}i;

	    my($inst) = $self->catfile($prefix,$striplibpath);
	    local($_) = $inst; # for backwards compatibility
	    $inst = $self->libscan($inst);
	    print "libscan($path) => '$inst'\n" if ($Verbose >= 2);
	    return unless $inst;
	    if ($self->{XSMULTI} and $inst =~ /\.xs\z/) {
		my($base); ($base = $path) =~ s/\.xs\z//;
		$self->{XS}{$path} = "$base.c";
		push @{$self->{C}}, "$base.c";
		push @{$self->{O_FILES}}, "$base$self->{OBJ_EXT}";
	    } else {
		$self->{PM}{$path} = $inst;
	    }
	}, @{$self->{PMLIBDIRS}});
    }
}


=item init_DIRFILESEP

Using / for Unix.  Called by init_main.

=cut

sub init_DIRFILESEP {
    my($self) = shift;

    $self->{DIRFILESEP} = '/';
}


=item init_main

Initializes AR, AR_STATIC_ARGS, BASEEXT, CONFIG, DISTNAME, DLBASE,
EXE_EXT, FULLEXT, FULLPERL, FULLPERLRUN, FULLPERLRUNINST, INST_*,
INSTALL*, INSTALLDIRS, LIB_EXT, LIBPERL_A, MAP_TARGET, NAME,
OBJ_EXT, PARENT_NAME, PERL, PERL_ARCHLIB, PERL_INC, PERL_LIB,
PERL_SRC, PERLRUN, PERLRUNINST, PREFIX, VERSION,
VERSION_SYM, XS_VERSION.

=cut

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

    # --- Initialize Module Name and Paths

    # NAME    = Foo::Bar::Oracle
    # FULLEXT = Foo/Bar/Oracle
    # BASEEXT = Oracle
    # PARENT_NAME = Foo::Bar
### Only UNIX:
###    ($self->{FULLEXT} =
###     $self->{NAME}) =~ s!::!/!g ; #eg. BSD/Foo/Socket
    $self->{FULLEXT} = $self->catdir(split /::/, $self->{NAME});


    # Copied from DynaLoader:

    my(@modparts) = split(/::/,$self->{NAME});
    my($modfname) = $modparts[-1];

    # Some systems have restrictions on files names for DLL's etc.
    # mod2fname returns appropriate file base name (typically truncated)
    # It may also edit @modparts if required.
    # We require DynaLoader to make sure that mod2fname is loaded
    eval { require DynaLoader };
    if (defined &DynaLoader::mod2fname) {
        $modfname = &DynaLoader::mod2fname(\@modparts);
    }

    ($self->{PARENT_NAME}, $self->{BASEEXT}) = $self->{NAME} =~ m!(?:([\w:]+)::)?(\w+)\z! ;
    $self->{PARENT_NAME} ||= '';

    if (defined &DynaLoader::mod2fname) {
	# As of 5.001m, dl_os2 appends '_'
	$self->{DLBASE} = $modfname;
    } else {
	$self->{DLBASE} = '$(BASEEXT)';
    }


    # --- Initialize PERL_LIB, PERL_SRC

    # *Real* information: where did we get these two from? ...
    my $inc_config_dir = dirname($INC{'Config.pm'});
    my $inc_carp_dir   = dirname($INC{'Carp.pm'});

    unless ($self->{PERL_SRC}){
        foreach my $dir_count (1..8) { # 8 is the VMS limit for nesting
            my $dir = $self->catdir(($Updir) x $dir_count);

            if (-f $self->catfile($dir,"config_h.SH")   &&
                -f $self->catfile($dir,"perl.h")        &&
                -f $self->catfile($dir,"lib","strict.pm")
            ) {
                $self->{PERL_SRC}=$dir ;
                last;
            }
        }
    }

    warn "PERL_CORE is set but I can't find your PERL_SRC!\n" if
      $self->{PERL_CORE} and !$self->{PERL_SRC};

    if ($self->{PERL_SRC}){
	$self->{PERL_LIB}     ||= $self->catdir("$self->{PERL_SRC}","lib");

        $self->{PERL_ARCHLIB} = $self->{PERL_LIB};
        $self->{PERL_INC}     = ($Is{Win32}) ?
            $self->catdir($self->{PERL_LIB},"CORE") : $self->{PERL_SRC};

	# catch a situation that has occurred a few times in the past:
	unless (
		-s $self->catfile($self->{PERL_SRC},'cflags')
		or
		$Is{VMS}
		&&
		-s $self->catfile($self->{PERL_SRC},'vmsish.h')
		or
		$Is{Win32}
	       ){
	    warn qq{
You cannot build extensions below the perl source tree after executing
a 'make clean' in the perl source tree.

To rebuild extensions distributed with the perl source you should
simply Configure (to include those extensions) and then build perl as
normal. After installing perl the source tree can be deleted. It is
not needed for building extensions by running 'perl Makefile.PL'
usually without extra arguments.

It is recommended that you unpack and build additional extensions away
from the perl source tree.
};
	}
    } else {
	# we should also consider $ENV{PERL5LIB} here
        my $old = $self->{PERL_LIB} || $self->{PERL_ARCHLIB} || $self->{PERL_INC};
	$self->{PERL_LIB}     ||= $Config{privlibexp};
	$self->{PERL_ARCHLIB} ||= $Config{archlibexp};
	$self->{PERL_INC}     = $self->catdir("$self->{PERL_ARCHLIB}","CORE"); # wild guess for now
	my $perl_h;

	if (not -f ($perl_h = $self->catfile($self->{PERL_INC},"perl.h"))
	    and not $old){
	    # Maybe somebody tries to build an extension with an
	    # uninstalled Perl outside of Perl build tree
	    my $lib;
	    for my $dir (@INC) {
	      $lib = $dir, last if -e $self->catfile($dir, "Config.pm");
	    }
	    if ($lib) {
              # Win32 puts its header files in /perl/src/lib/CORE.
              # Unix leaves them in /perl/src.
	      my $inc = $Is{Win32} ? $self->catdir($lib, "CORE" )
                                  : dirname $lib;
	      if (-e $self->catfile($inc, "perl.h")) {
		$self->{PERL_LIB}	   = $lib;
		$self->{PERL_ARCHLIB}	   = $lib;
		$self->{PERL_INC}	   = $inc;
		$self->{UNINSTALLED_PERL}  = 1;
		print <<EOP;
... Detected uninstalled Perl.  Trying to continue.
EOP
	      }
	    }
	}
    }

    if ($Is{Android}) {
    	# Android fun times!
    	# ../../perl -I../../lib -MFile::Glob -e1 works
    	# ../../../perl -I../../../lib -MFile::Glob -e1 fails to find
    	# the .so for File::Glob.
    	# This always affects core perl, but may also affect an installed
    	# perl built with -Duserelocatableinc.
    	$self->{PERL_LIB} = File::Spec->rel2abs($self->{PERL_LIB});
    	$self->{PERL_ARCHLIB} = File::Spec->rel2abs($self->{PERL_ARCHLIB});
    }
    $self->{PERL_INCDEP} = $self->{PERL_INC};
    $self->{PERL_ARCHLIBDEP} = $self->{PERL_ARCHLIB};

    # We get SITELIBEXP and SITEARCHEXP directly via
    # Get_from_Config. When we are running standard modules, these
    # won't matter, we will set INSTALLDIRS to "perl". Otherwise we
    # set it to "site". I prefer that INSTALLDIRS be set from outside
    # MakeMaker.
    $self->{INSTALLDIRS} ||= "site";

    $self->{MAN1EXT} ||= $Config{man1ext};
    $self->{MAN3EXT} ||= $Config{man3ext};

    # Get some stuff out of %Config if we haven't yet done so
    print "CONFIG must be an array ref\n"
        if ($self->{CONFIG} and ref $self->{CONFIG} ne 'ARRAY');
    $self->{CONFIG} = [] unless (ref $self->{CONFIG});
    push(@{$self->{CONFIG}}, @ExtUtils::MakeMaker::Get_from_Config);
    push(@{$self->{CONFIG}}, 'shellflags') if $Config{shellflags};
    my(%once_only);
    foreach my $m (@{$self->{CONFIG}}){
        next if $once_only{$m};
        print "CONFIG key '$m' does not exist in Config.pm\n"
                unless exists $Config{$m};
        $self->{uc $m} ||= $Config{$m};
        $once_only{$m} = 1;
    }

# This is too dangerous:
#    if ($^O eq "next") {
#	$self->{AR} = "libtool";
#	$self->{AR_STATIC_ARGS} = "-o";
#    }
# But I leave it as a placeholder

    $self->{AR_STATIC_ARGS} ||= "cr";

    # These should never be needed
    $self->{OBJ_EXT} ||= '.o';
    $self->{LIB_EXT} ||= '.a';

    $self->{MAP_TARGET} ||= "perl";

    $self->{LIBPERL_A} ||= "libperl$self->{LIB_EXT}";

    # make a simple check if we find strict
    warn "Warning: PERL_LIB ($self->{PERL_LIB}) seems not to be a perl library directory
        (strict.pm not found)"
        unless -f $self->catfile("$self->{PERL_LIB}","strict.pm") ||
               $self->{NAME} eq "ExtUtils::MakeMaker";
}

=item init_tools

Initializes tools to use their common (and faster) Unix commands.

=cut

sub init_tools {
    my $self = shift;

    $self->{ECHO}       ||= 'echo';
    $self->{ECHO_N}     ||= 'echo -n';
    $self->{RM_F}       ||= "rm -f";
    $self->{RM_RF}      ||= "rm -rf";
    $self->{TOUCH}      ||= "touch";
    $self->{TEST_F}     ||= "test -f";
    $self->{TEST_S}     ||= "test -s";
    $self->{CP}         ||= "cp";
    $self->{MV}         ||= "mv";
    $self->{CHMOD}      ||= "chmod";
    $self->{FALSE}      ||= 'false';
    $self->{TRUE}       ||= 'true';

    $self->{LD}         ||= 'ld';

    return $self->SUPER::init_tools(@_);

    # After SUPER::init_tools so $Config{shell} has a
    # chance to get set.
    $self->{SHELL}      ||= '/bin/sh';

    return;
}


=item init_linker

Unix has no need of special linker flags.

=cut

sub init_linker {
    my($self) = shift;
    $self->{PERL_ARCHIVE} ||= '';
    $self->{PERL_ARCHIVEDEP} ||= '';
    $self->{PERL_ARCHIVE_AFTER} ||= '';
    $self->{EXPORT_LIST}  ||= '';
}


=begin _protected

=item init_lib2arch

    $mm->init_lib2arch

=end _protected

=cut

sub init_lib2arch {
    my($self) = shift;

    # The user who requests an installation directory explicitly
    # should not have to tell us an architecture installation directory
    # as well. We look if a directory exists that is named after the
    # architecture. If not we take it as a sign that it should be the
    # same as the requested installation directory. Otherwise we take
    # the found one.
    for my $libpair ({l=>"privlib",   a=>"archlib"},
                     {l=>"sitelib",   a=>"sitearch"},
                     {l=>"vendorlib", a=>"vendorarch"},
                    )
    {
        my $lib = "install$libpair->{l}";
        my $Lib = uc $lib;
        my $Arch = uc "install$libpair->{a}";
        if( $self->{$Lib} && ! $self->{$Arch} ){
            my($ilib) = $Config{$lib};

            $self->prefixify($Arch,$ilib,$self->{$Lib});

            unless (-d $self->{$Arch}) {
                print "Directory $self->{$Arch} not found\n"
                  if $Verbose;
                $self->{$Arch} = $self->{$Lib};
            }
            print "Defaulting $Arch to $self->{$Arch}\n" if $Verbose;
        }
    }
}


=item init_PERL

    $mm->init_PERL;

Called by init_main.  Sets up ABSPERL, PERL, FULLPERL and all the
*PERLRUN* permutations.

    PERL is allowed to be miniperl
    FULLPERL must be a complete perl

    ABSPERL is PERL converted to an absolute path

    *PERLRUN contains everything necessary to run perl, find it's
         libraries, etc...

    *PERLRUNINST is *PERLRUN + everything necessary to find the
         modules being built.

=cut

sub init_PERL {
    my($self) = shift;

    my @defpath = ();
    foreach my $component ($self->{PERL_SRC}, $self->path(),
                           $Config{binexp})
    {
	push @defpath, $component if defined $component;
    }

    # Build up a set of file names (not command names).
    my $thisperl = $self->canonpath($^X);
    $thisperl .= $Config{exe_ext} unless
                # VMS might have a file version # at the end
      $Is{VMS} ? $thisperl =~ m/$Config{exe_ext}(;\d+)?$/i
              : $thisperl =~ m/$Config{exe_ext}$/i;

    # We need a relative path to perl when in the core.
    $thisperl = $self->abs2rel($thisperl) if $self->{PERL_CORE};

    my @perls = ($thisperl);
    push @perls, map { "$_$Config{exe_ext}" }
                     ("perl$Config{version}", 'perl5', 'perl');

    # miniperl has priority over all but the canonical perl when in the
    # core.  Otherwise its a last resort.
    my $miniperl = "miniperl$Config{exe_ext}";
    if( $self->{PERL_CORE} ) {
        splice @perls, 1, 0, $miniperl;
    }
    else {
        push @perls, $miniperl;
    }

    $self->{PERL} ||=
        $self->find_perl(5.0, \@perls, \@defpath, $Verbose );

    my $perl = $self->{PERL};
    $perl =~ s/^"//;
    my $has_mcr = $perl =~ s/^MCR\s*//;
    my $perlflags = '';
    my $stripped_perl;
    while ($perl) {
	($stripped_perl = $perl) =~ s/"$//;
	last if -x $stripped_perl;
	last unless $perl =~ s/(\s+\S+)$//;
	$perlflags = $1.$perlflags;
    }
    $self->{PERL} = $stripped_perl;
    $self->{PERL} = 'MCR '.$self->{PERL} if $has_mcr || $Is{VMS};

    # When built for debugging, VMS doesn't create perl.exe but ndbgperl.exe.
    my $perl_name = 'perl';
    $perl_name = 'ndbgperl' if $Is{VMS} &&
      defined $Config{usevmsdebug} && $Config{usevmsdebug} eq 'define';

    # XXX This logic is flawed.  If "miniperl" is anywhere in the path
    # it will get confused.  It should be fixed to work only on the filename.
    # Define 'FULLPERL' to be a non-miniperl (used in test: target)
    unless ($self->{FULLPERL}) {
      ($self->{FULLPERL} = $self->{PERL}) =~ s/\Q$miniperl\E$/$perl_name$Config{exe_ext}/i;
      $self->{FULLPERL} = qq{"$self->{FULLPERL}"}.$perlflags;
    }
    # Can't have an image name with quotes, and findperl will have
    # already escaped spaces.
    $self->{FULLPERL} =~ tr/"//d if $Is{VMS};

    # `dmake` can fail for image (aka, executable) names which start with double-quotes
    # * push quote inward by at least one character (or the drive prefix, if present)
    # * including any initial directory separator preserves the `file_name_is_absolute` property
    $self->{FULLPERL} =~ s/^"(\S(:\\|:)?)/$1"/ if $self->is_make_type('dmake');

    # Little hack to get around VMS's find_perl putting "MCR" in front
    # sometimes.
    $self->{ABSPERL} = $self->{PERL};
    $has_mcr = $self->{ABSPERL} =~ s/^MCR\s*//;
    if( $self->file_name_is_absolute($self->{ABSPERL}) ) {
        $self->{ABSPERL} = '$(PERL)';
    }
    else {
        $self->{ABSPERL} = $self->rel2abs($self->{ABSPERL});

        # Quote the perl command if it contains whitespace
        $self->{ABSPERL} = $self->quote_literal($self->{ABSPERL})
          if $self->{ABSPERL} =~ /\s/;

        $self->{ABSPERL} = 'MCR '.$self->{ABSPERL} if $has_mcr;
    }
    $self->{PERL} = qq{"$self->{PERL}"}.$perlflags;

    # Can't have an image name with quotes, and findperl will have
    # already escaped spaces.
    $self->{PERL} =~ tr/"//d if $Is{VMS};

    # `dmake` can fail for image (aka, executable) names which start with double-quotes
    # * push quote inward by at least one character (or the drive prefix, if present)
    # * including any initial directory separator preserves the `file_name_is_absolute` property
    $self->{PERL} =~ s/^"(\S(:\\|:)?)/$1"/ if $self->is_make_type('dmake');

    # Are we building the core?
    $self->{PERL_CORE} = $ENV{PERL_CORE} unless exists $self->{PERL_CORE};
    $self->{PERL_CORE} = 0               unless defined $self->{PERL_CORE};

    # Make sure perl can find itself before it's installed.
    my $lib_paths = $self->{UNINSTALLED_PERL} || $self->{PERL_CORE}
        ? ( $self->{PERL_ARCHLIB} && $self->{PERL_LIB} && $self->{PERL_ARCHLIB} ne $self->{PERL_LIB} ) ?
            q{ "-I$(PERL_LIB)" "-I$(PERL_ARCHLIB)"} : q{ "-I$(PERL_LIB)"}
        : undef;
    my $inst_lib_paths = $self->{INST_ARCHLIB} ne $self->{INST_LIB}
        ? 'RUN)'.$perlflags.' "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"'
        : 'RUN)'.$perlflags.' "-I$(INST_LIB)"';
    # How do we run perl?
    foreach my $perl (qw(PERL FULLPERL ABSPERL)) {
        my $run  = $perl.'RUN';

        $self->{$run}  = qq{\$($perl)};
        $self->{$run} .= $lib_paths if $lib_paths;

        $self->{$perl.'RUNINST'} = '$('.$perl.$inst_lib_paths;
    }

    return 1;
}


=item init_platform

=item platform_constants

Add MM_Unix_VERSION.

=cut

sub init_platform {
    my($self) = shift;

    $self->{MM_Unix_VERSION} = $VERSION;
    $self->{PERL_MALLOC_DEF} = '-DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc '.
                               '-Dfree=Perl_mfree -Drealloc=Perl_realloc '.
                               '-Dcalloc=Perl_calloc';

}

sub platform_constants {
    my($self) = shift;
    my $make_frag = '';

    foreach my $macro (qw(MM_Unix_VERSION PERL_MALLOC_DEF))
    {
        next unless defined $self->{$macro};
        $make_frag .= "$macro = $self->{$macro}\n";
    }

    return $make_frag;
}


=item init_PERM

  $mm->init_PERM

Called by init_main.  Initializes PERL_*

=cut

sub init_PERM {
    my($self) = shift;

    $self->{PERM_DIR} = 755  unless defined $self->{PERM_DIR};
    $self->{PERM_RW}  = 644  unless defined $self->{PERM_RW};
    $self->{PERM_RWX} = 755  unless defined $self->{PERM_RWX};

    return 1;
}


=item init_xs

    $mm->init_xs

Sets up macros having to do with XS code.  Currently just INST_STATIC,
INST_DYNAMIC and INST_BOOT.

=cut

sub init_xs {
    my $self = shift;

    if ($self->has_link_code()) {
        $self->{INST_STATIC}  =
          $self->catfile('$(INST_ARCHAUTODIR)', '$(BASEEXT)$(LIB_EXT)');
        $self->{INST_DYNAMIC} =
          $self->catfile('$(INST_ARCHAUTODIR)', '$(DLBASE).$(DLEXT)');
        $self->{INST_BOOT}    =
          $self->catfile('$(INST_ARCHAUTODIR)', '$(BASEEXT).bs');
	if ($self->{XSMULTI}) {
	    my @exts = $self->_xs_list_basenames;
	    my (@statics, @dynamics, @boots);
	    for my $ext (@exts) {
		my ($v, $d, $f) = File::Spec->splitpath($ext);
		my @d = File::Spec->splitdir($d);
		shift @d if defined $d[0] and $d[0] eq 'lib';
		pop @d if $d[$#d] eq '';
		my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
		my $instfile = $self->catfile($instdir, $f);
		push @statics, "$instfile\$(LIB_EXT)";

                # Dynamic library names may need special handling.
                my $dynfile = $instfile;
                eval { require DynaLoader };
                if (defined &DynaLoader::mod2fname) {
                    $dynfile = $self->catfile($instdir, &DynaLoader::mod2fname([@d, $f]));
                }

		push @dynamics, "$dynfile.\$(DLEXT)";
		push @boots, "$instfile.bs";
	    }
	    $self->{INST_STATIC} = join ' ', @statics;
	    $self->{INST_DYNAMIC} = join ' ', @dynamics;
	    $self->{INST_BOOT} = join ' ', @boots;
	}
    } else {
        $self->{INST_STATIC}  = '';
        $self->{INST_DYNAMIC} = '';
        $self->{INST_BOOT}    = '';
    }
}

=item install (o)

Defines the install target.

=cut

sub install {
    my($self, %attribs) = @_;
    my(@m);

    push @m, q{
install :: pure_install doc_install
	$(NOECHO) $(NOOP)

install_perl :: pure_perl_install doc_perl_install
	$(NOECHO) $(NOOP)

install_site :: pure_site_install doc_site_install
	$(NOECHO) $(NOOP)

install_vendor :: pure_vendor_install doc_vendor_install
	$(NOECHO) $(NOOP)

pure_install :: pure_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

doc_install :: doc_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

pure__install : pure_site_install
	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

doc__install : doc_site_install
	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

pure_perl_install :: all
	$(NOECHO) umask 022; $(MOD_INSTALL) \
};

    push @m,
q{		"$(INST_LIB)" "$(DESTINSTALLPRIVLIB)" \
		"$(INST_ARCHLIB)" "$(DESTINSTALLARCHLIB)" \
		"$(INST_BIN)" "$(DESTINSTALLBIN)" \
		"$(INST_SCRIPT)" "$(DESTINSTALLSCRIPT)" \
		"$(INST_MAN1DIR)" "$(DESTINSTALLMAN1DIR)" \
		"$(INST_MAN3DIR)" "$(DESTINSTALLMAN3DIR)"
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
		"}.$self->catdir('$(SITEARCHEXP)','auto','$(FULLEXT)').q{"


pure_site_install :: all
	$(NOECHO) umask 02; $(MOD_INSTALL) \
};
    push @m,
q{		read "}.$self->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').q{" \
		write "}.$self->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').q{" \
} unless $self->{NO_PACKLIST};

    push @m,
q{		"$(INST_LIB)" "$(DESTINSTALLSITELIB)" \
		"$(INST_ARCHLIB)" "$(DESTINSTALLSITEARCH)" \
		"$(INST_BIN)" "$(DESTINSTALLSITEBIN)" \
		"$(INST_SCRIPT)" "$(DESTINSTALLSITESCRIPT)" \
		"$(INST_MAN1DIR)" "$(DESTINSTALLSITEMAN1DIR)" \
		"$(INST_MAN3DIR)" "$(DESTINSTALLSITEMAN3DIR)"
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
		"}.$self->catdir('$(PERL_ARCHLIB)','auto','$(FULLEXT)').q{"

pure_vendor_install :: all
	$(NOECHO) umask 022; $(MOD_INSTALL) \
};

    push @m,
q{		"$(INST_LIB)" "$(DESTINSTALLVENDORLIB)" \
		"$(INST_ARCHLIB)" "$(DESTINSTALLVENDORARCH)" \
		"$(INST_BIN)" "$(DESTINSTALLVENDORBIN)" \
		"$(INST_SCRIPT)" "$(DESTINSTALLVENDORSCRIPT)" \
		"$(INST_MAN1DIR)" "$(DESTINSTALLVENDORMAN1DIR)" \
		"$(INST_MAN3DIR)" "$(DESTINSTALLVENDORMAN3DIR)"

};

    push @m, q{
doc_perl_install :: all
	$(NOECHO) $(NOOP)

doc_site_install :: all
	$(NOECHO) $(NOOP)

doc_vendor_install :: all
	$(NOECHO) $(NOOP)

} if $self->{NO_PERLLOCAL};

    push @m, q{
doc_perl_install :: all

doc_site_install :: all
	$(NOECHO) $(ECHO) Appending installation info to "$(DESTINSTALLSITEARCH)/perllocal.pod"
	-$(NOECHO) umask 02; $(MKPATH) "$(DESTINSTALLSITEARCH)"
	-$(NOECHO) umask 02; $(DOC_INSTALL) \
		"Module" "$(NAME)" \
		"installed into" "$(INSTALLSITELIB)" \
		LINKTYPE "$(LINKTYPE)" \
		VERSION "$(VERSION)" \
		EXE_FILES "$(EXE_FILES)" \
		>> "}.$self->catfile('$(DESTINSTALLSITEARCH)','perllocal.pod').q{"

doc_vendor_install :: all

} unless $self->{NO_PERLLOCAL};

    push @m, q{
uninstall :: uninstall_from_$(INSTALLDIRS)dirs
	$(NOECHO) $(NOOP)

uninstall_from_perldirs ::

uninstall_from_sitedirs ::
	$(NOECHO) $(UNINSTALL) "}.$self->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').q{"

uninstall_from_vendordirs ::
};

    join("",@m);
}

=item installbin (o)

Defines targets to make and to install EXE_FILES.

=cut

sub installbin {
    my($self) = shift;

    return "" unless $self->{EXE_FILES} && ref $self->{EXE_FILES} eq "ARRAY";
    my @exefiles = sort @{$self->{EXE_FILES}};
    return "" unless @exefiles;

    @exefiles = map vmsify($_), @exefiles if $Is{VMS};

    my %fromto;
    for my $from (@exefiles) {
	my($path)= $self->catfile('$(INST_SCRIPT)', basename($from));

	local($_) = $path; # for backwards compatibility
	my $to = $self->libscan($path);
	print "libscan($from) => '$to'\n" if ($Verbose >=2);

        $to = vmsify($to) if $Is{VMS};
	$fromto{$from} = $to;
    }
    my @to   = sort values %fromto;

    my @m;
    push(@m, qq{
EXE_FILES = @exefiles

pure_all :: @to
	\$(NOECHO) \$(NOOP)

realclean ::
});

    # realclean can get rather large.
    push @m, map "\t$_\n", $self->split_command('$(RM_F)', @to);
    push @m, "\n";

    # A target for each exe file.
    my @froms = sort keys %fromto;
    for my $from (@froms) {
        #                              1      2
        push @m, _sprintf562 <<'MAKE', $from, $fromto{$from};
%2$s : %1$s $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
	$(NOECHO) $(RM_F) %2$s
	$(CP) %1$s %2$s
	$(FIXIN) %2$s
	-$(NOECHO) $(CHMOD) $(PERM_RWX) %2$s

MAKE

    }

    join "", @m;
}

=item linkext (o)

Defines the linkext target which in turn defines the LINKTYPE.

=cut

# LINKTYPE => static or dynamic or ''
sub linkext {
    my($self, %attribs) = @_;
    my $linktype = $attribs{LINKTYPE};
    $linktype = $self->{LINKTYPE} unless defined $linktype;
    if (defined $linktype and $linktype eq '') {
        warn "Warning: LINKTYPE set to '', no longer necessary\n";
    }
    $linktype = '$(LINKTYPE)' unless defined $linktype;
    "
linkext :: $linktype
	\$(NOECHO) \$(NOOP)
";
}

=item lsdir

Takes as arguments a directory name and a regular expression. Returns
all entries in the directory that match the regular expression.

=cut

sub lsdir {
    #  $self
    my(undef, $dir, $regex) = @_;
    opendir(my $dh, defined($dir) ? $dir : ".")
        or return;
    my @ls = readdir $dh;
    closedir $dh;
    @ls = grep(/$regex/, @ls) if defined $regex;
    @ls;
}

=item macro (o)

Simple subroutine to insert the macros defined by the macro attribute
into the Makefile.

=cut

sub macro {
    my($self,%attribs) = @_;
    my @m;
    foreach my $key (sort keys %attribs) {
	my $val = $attribs{$key};
	push @m, "$key = $val\n";
    }
    join "", @m;
}

=item makeaperl (o)

Called by staticmake. Defines how to write the Makefile to produce a
static new perl.

By default the Makefile produced includes all the static extensions in
the perl library. (Purified versions of library files, e.g.,
DynaLoader_pure_p1_c0_032.a are automatically ignored to avoid link errors.)

=cut

sub makeaperl {
    my($self, %attribs) = @_;
    my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmp, $libperl) =
	@attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)};
    s/^(.*)/"-I$1"/ for @{$perlinc || []};
    my(@m);
    push @m, "
# --- MakeMaker makeaperl section ---
MAP_TARGET    = $target
FULLPERL      = $self->{FULLPERL}
MAP_PERLINC   = @{$perlinc || []}
";
    return join '', @m if $self->{PARENT};

    my($dir) = join ":", @{$self->{DIR}};

    unless ($self->{MAKEAPERL}) {
	push @m, q{
$(MAP_TARGET) :: $(MAKE_APERL_FILE)
	$(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@

$(MAKE_APERL_FILE) : static $(FIRST_MAKEFILE) pm_to_blib
	$(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET)
	$(NOECHO) $(PERLRUNINST) \
		Makefile.PL DIR="}, $dir, q{" \
		MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
		MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=};

	foreach (@ARGV){
		my $arg = $_; # avoid lvalue aliasing
		if ( $arg =~ /(^.*?=)(.*['\s].*)/ ) {
			$arg = $1 . $self->quote_literal($2);
		}
		push @m, " \\\n\t\t$arg";
	}
	push @m, "\n";

	return join '', @m;
    }

    my $cccmd = $self->const_cccmd($libperl);
    $cccmd =~ s/^CCCMD\s*=\s*//;
    $cccmd =~ s/\$\(INC\)/ "-I$self->{PERL_INC}" /;
    $cccmd .= " $Config{cccdlflags}"
	if ($Config{useshrplib} eq 'true');
    $cccmd =~ s/\(CC\)/\(PERLMAINCC\)/;

    # The front matter of the linkcommand...
    my $linkcmd = join ' ', "\$(CC)",
	    grep($_, @Config{qw(ldflags ccdlflags)});
    $linkcmd =~ s/\s+/ /g;
    $linkcmd =~ s,(perl\.exp),\$(PERL_INC)/$1,;

    # Which *.a files could we make use of...
    my $staticlib21 = $self->_find_static_libs($searchdirs);
    # We trust that what has been handed in as argument, will be buildable
    $static = [] unless $static;
    @$staticlib21{@{$static}} = (1) x @{$static};

    $extra = [] unless $extra && ref $extra eq 'ARRAY';
    for (sort keys %$staticlib21) {
	next unless /\Q$self->{LIB_EXT}\E\z/;
	$_ = dirname($_) . "/extralibs.ld";
	push @$extra, $_;
    }

    s/^(.*)/"-I$1"/ for @{$perlinc || []};

    $target ||= "perl";
    $tmp    ||= ".";

# MAP_STATIC doesn't look into subdirs yet. Once "all" is made and we
# regenerate the Makefiles, MAP_STATIC and the dependencies for
# extralibs.all are computed correctly
    my @map_static = reverse sort keys %$staticlib21;
    push @m, "
MAP_LINKCMD   = $linkcmd
MAP_STATIC    = ", join(" \\\n\t", map { qq{"$_"} } @map_static), "
MAP_STATICDEP = ", join(' ', map { $self->quote_dep($_) } @map_static), "

MAP_PRELIBS   = $Config{perllibs} $Config{cryptlib}
";

    my $lperl;
    if (defined $libperl) {
	($lperl = $libperl) =~ s/\$\(A\)/$self->{LIB_EXT}/;
    }
    unless ($libperl && -f $lperl) { # Ilya's code...
	my $dir = $self->{PERL_SRC} || "$self->{PERL_ARCHLIB}/../..";
	$dir = "$self->{PERL_ARCHLIB}/.." if $self->{UNINSTALLED_PERL};
	$libperl ||= "libperl$self->{LIB_EXT}";
	$libperl   = "$dir/$libperl";
	$lperl   ||= "libperl$self->{LIB_EXT}";
	$lperl     = "$dir/$lperl";

        if (! -f $libperl and ! -f $lperl) {
          # We did not find a static libperl. Maybe there is a shared one?
          if ($Is{SunOS}) {
            $lperl  = $libperl = "$dir/$Config{libperl}";
            # SUNOS ld does not take the full path to a shared library
            $libperl = '' if $Is{SunOS4};
          }
        }

	print <<EOF unless -f $lperl || defined($self->{PERL_SRC});
Warning: $libperl not found
If you're going to build a static perl binary, make sure perl is installed
otherwise ignore this warning
EOF
    }

    # SUNOS ld does not take the full path to a shared library
    my $llibperl = $libperl ? '$(MAP_LIBPERL)' : '-lperl';
    my $libperl_dep = $self->quote_dep($libperl);

    push @m, "
MAP_LIBPERL = $libperl
MAP_LIBPERLDEP = $libperl_dep
LLIBPERL    = $llibperl
";

    push @m, '
$(INST_ARCHAUTODIR)/extralibs.all : $(INST_ARCHAUTODIR)$(DFSEP).exists '.join(" \\\n\t", @$extra).'
	$(NOECHO) $(RM_F)  $@
	$(NOECHO) $(TOUCH) $@
';

    foreach my $catfile (@$extra){
	push @m, "\tcat $catfile >> \$\@\n";
    }

    my $ldfrom = $self->{XSMULTI} ? '' : '$(LDFROM)';
    #                             1     2                        3        4
    push @m, _sprintf562 <<'EOF', $tmp, $ldfrom, $self->xs_obj_opt('$@'), $makefilename;
$(MAP_TARGET) :: %1$s/perlmain$(OBJ_EXT) $(MAP_LIBPERLDEP) $(MAP_STATICDEP) $(INST_ARCHAUTODIR)/extralibs.all
	$(MAP_LINKCMD) %2$s $(OPTIMIZE) %1$s/perlmain$(OBJ_EXT) %3$s $(MAP_STATIC) "$(LLIBPERL)" `cat $(INST_ARCHAUTODIR)/extralibs.all` $(MAP_PRELIBS)
	$(NOECHO) $(ECHO) "To install the new '$(MAP_TARGET)' binary, call"
	$(NOECHO) $(ECHO) "    $(MAKE) $(USEMAKEFILE) %4$s inst_perl MAP_TARGET=$(MAP_TARGET)"
	$(NOECHO) $(ECHO) "    $(MAKE) $(USEMAKEFILE) %4$s map_clean"

%1$s/perlmain\$(OBJ_EXT): %1$s/perlmain.c
EOF
    push @m, "\t".$self->cd($tmp, qq[$cccmd "-I\$(PERL_INC)" perlmain.c])."\n";

    my $maybe_DynaLoader = $Config{usedl} ? 'q(DynaLoader)' : '';
    push @m, _sprintf562 <<'EOF', $tmp, $makefilename, $maybe_DynaLoader;

%1$s/perlmain.c: %2$s
	$(NOECHO) $(ECHO) Writing $@
	$(NOECHO) $(PERL) $(MAP_PERLINC) "-MExtUtils::Miniperl" \
		-e "writemain(grep(s#.*/auto/##s, @ARGV), %3$s)" $(MAP_STATIC) > $@t
	$(MV) $@t $@

EOF
    push @m, "\t", q{$(NOECHO) $(PERL) "$(INSTALLSCRIPT)/fixpmain"
} if (defined (&Dos::UseLFN) && Dos::UseLFN()==0);


    push @m, q{
doc_inst_perl :
	$(NOECHO) $(ECHO) Appending installation info to "$(DESTINSTALLARCHLIB)/perllocal.pod"
	-$(NOECHO) $(MKPATH) "$(DESTINSTALLARCHLIB)"
	-$(NOECHO) $(DOC_INSTALL) \
		"Perl binary" "$(MAP_TARGET)" \
		MAP_STATIC "$(MAP_STATIC)" \
		MAP_EXTRA "`cat $(INST_ARCHAUTODIR)/extralibs.all`" \
		MAP_LIBPERL "$(MAP_LIBPERL)" \
		>> "}.$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q{"

};

    push @m, q{
inst_perl : pure_inst_perl doc_inst_perl

pure_inst_perl : $(MAP_TARGET)
	}.$self->{CP}.q{ $(MAP_TARGET) "}.$self->catfile('$(DESTINSTALLBIN)','$(MAP_TARGET)').q{"

clean :: map_clean

map_clean :
	}.$self->{RM_F}.qq{ $tmp/perlmain\$(OBJ_EXT) $tmp/perlmain.c \$(MAP_TARGET) $makefilename \$(INST_ARCHAUTODIR)/extralibs.all
};

    join '', @m;
}

# utility method
sub _find_static_libs {
    my ($self, $searchdirs) = @_;
    # don't use File::Spec here because on Win32 F::F still uses "/"
    my $installed_version = join('/',
	'auto', $self->{FULLEXT}, "$self->{BASEEXT}$self->{LIB_EXT}"
    );
    my %staticlib21;
    require File::Find;
    File::Find::find(sub {
	if ($File::Find::name =~ m{/auto/share\z}) {
	    # in a subdir of auto/share, prune because e.g.
	    # Alien::pkgconfig uses File::ShareDir to put .a files
	    # there. do not want
	    $File::Find::prune = 1;
	    return;
	}

	return unless m/\Q$self->{LIB_EXT}\E$/;

	return unless -f 'extralibs.ld'; # this checks is a "proper" XS installation

        # Skip perl's libraries.
        return if m/^libperl/ or m/^perl\Q$self->{LIB_EXT}\E$/;

	# Skip purified versions of libraries
        # (e.g., DynaLoader_pure_p1_c0_032.a)
	return if m/_pure_\w+_\w+_\w+\.\w+$/ and -f "$File::Find::dir/.pure";

	if( exists $self->{INCLUDE_EXT} ){
		my $found = 0;

		(my $xx = $File::Find::name) =~ s,.*?/auto/,,s;
		$xx =~ s,/?$_,,;
		$xx =~ s,/,::,g;

		# Throw away anything not explicitly marked for inclusion.
		# DynaLoader is implied.
		foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){
			if( $xx eq $incl ){
				$found++;
				last;
			}
		}
		return unless $found;
	}
	elsif( exists $self->{EXCLUDE_EXT} ){
		(my $xx = $File::Find::name) =~ s,.*?/auto/,,s;
		$xx =~ s,/?$_,,;
		$xx =~ s,/,::,g;

		# Throw away anything explicitly marked for exclusion
		foreach my $excl (@{$self->{EXCLUDE_EXT}}){
			return if( $xx eq $excl );
		}
	}

	# don't include the installed version of this extension. I
	# leave this line here, although it is not necessary anymore:
	# I patched minimod.PL instead, so that Miniperl.pm won't
	# include duplicates

	# Once the patch to minimod.PL is in the distribution, I can
	# drop it
	return if $File::Find::name =~ m:\Q$installed_version\E\z:;
	return if !$self->xs_static_lib_is_xs($_);
	use Cwd 'cwd';
	$staticlib21{cwd() . "/" . $_}++;
    }, grep( -d $_, map { $self->catdir($_, 'auto') } @{$searchdirs || []}) );
    return \%staticlib21;
}

=item xs_static_lib_is_xs (o)

Called by a utility method of makeaperl. Checks whether a given file
is an XS library by seeing whether it defines any symbols starting
with C<boot_> (with an optional leading underscore - needed on MacOS).

=cut

sub xs_static_lib_is_xs {
    my ($self, $libfile) = @_;
    my $devnull = File::Spec->devnull;
    return `nm $libfile 2>$devnull` =~ /\b_?boot_/;
}

=item makefile (o)

Defines how to rewrite the Makefile.

=cut

sub makefile {
    my($self) = shift;
    my $m;
    # We do not know what target was originally specified so we
    # must force a manual rerun to be sure. But as it should only
    # happen very rarely it is not a significant problem.
    $m = '
$(OBJECT) : $(FIRST_MAKEFILE)

' if $self->{OBJECT};

    my $newer_than_target = $Is{VMS} ? '$(MMS$SOURCE_LIST)' : '$?';
    my $mpl_args = join " ", map qq["$_"], @ARGV;
    my $cross = '';
    if (defined $::Cross::platform) {
        # Inherited from win32/buildext.pl
        $cross = "-MCross=$::Cross::platform ";
    }
    $m .= sprintf <<'MAKE_FRAG', $newer_than_target, $cross, $mpl_args;
# We take a very conservative approach here, but it's worth it.
# We move Makefile to Makefile.old here to avoid gnu make looping.
$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP)
	$(NOECHO) $(ECHO) "Makefile out-of-date with respect to %s"
	$(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..."
	-$(NOECHO) $(RM_F) $(MAKEFILE_OLD)
	-$(NOECHO) $(MV)   $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
	- $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL)
	$(PERLRUN) %sMakefile.PL %s
	$(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <=="
	$(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command.  <=="
	$(FALSE)

MAKE_FRAG

    return $m;
}


=item maybe_command

Returns true, if the argument is likely to be a command.

=cut

sub maybe_command {
    my($self,$file) = @_;
    return $file if -x $file && ! -d $file;
    return;
}


=item needs_linking (o)

Does this module need linking? Looks into subdirectory objects (see
also has_link_code())

=cut

sub needs_linking {
    my($self) = shift;

    my $caller = (caller(0))[3];
    confess("needs_linking called too early") if
      $caller =~ /^ExtUtils::MakeMaker::/;
    return $self->{NEEDS_LINKING} if defined $self->{NEEDS_LINKING};
    if ($self->has_link_code or $self->{MAKEAPERL}){
	$self->{NEEDS_LINKING} = 1;
	return 1;
    }
    foreach my $child (keys %{$self->{CHILDREN}}) {
	if ($self->{CHILDREN}->{$child}->needs_linking) {
	    $self->{NEEDS_LINKING} = 1;
	    return 1;
	}
    }
    return $self->{NEEDS_LINKING} = 0;
}


=item parse_abstract

parse a file and return what you think is the ABSTRACT

=cut

sub parse_abstract {
    my($self,$parsefile) = @_;
    my $result;

    local $/ = "\n";
    open(my $fh, '<', $parsefile) or die "Could not open '$parsefile': $!";
    binmode $fh;
    my $inpod = 0;
    my $pod_encoding;
    my $package = $self->{DISTNAME};
    $package =~ s/-/::/g;
    while (<$fh>) {
        $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
        next if !$inpod;
        s#\r*\n\z##; # handle CRLF input

        if ( /^=encoding\s*(.*)$/i ) {
            $pod_encoding = $1;
        }

        if ( /^($package(?:\.pm)? \s+ -+ \s+)(.*)/x ) {
          $result = $2;
          next;
        }
        next unless $result;

        if ( $result && ( /^\s*$/ || /^\=/ ) ) {
          last;
        }
        $result = join ' ', $result, $_;
    }
    close $fh;

    if ( $pod_encoding and !( "$]" < 5.008 or !$Config{useperlio} ) ) {
        # Have to wrap in an eval{} for when running under PERL_CORE
        # Encode isn't available during build phase and parsing
        # ABSTRACT isn't important there
        eval {
          require Encode;
          $result = Encode::decode($pod_encoding, $result);
        }
    }

    return $result;
}

=item parse_version

    my $version = MM->parse_version($file);

Parse a $file and return what $VERSION is set to by the first assignment.
It will return the string "undef" if it can't figure out what $VERSION
is. $VERSION should be for all to see, so C<our $VERSION> or plain $VERSION
are okay, but C<my $VERSION> is not.

C<package Foo VERSION> is also checked for.  The first version
declaration found is used, but this may change as it differs from how
Perl does it.

parse_version() will try to C<use version> before checking for
C<$VERSION> so the following will work.

    $VERSION = qv(1.2.3);

=cut

sub parse_version {
    my($self,$parsefile) = @_;
    my $result;

    local $/ = "\n";
    local $_;
    open(my $fh, '<', $parsefile) or die "Could not open '$parsefile': $!";
    my $inpod = 0;
    while (<$fh>) {
        $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
        next if $inpod || /^\s*#/;
        chop;
        next if /^\s*(if|unless|elsif)/;
        if ( m{^ \s* package \s+ \w[\w\:\']* \s+ (v?[0-9._]+) \s* (;|\{)  }x ) {
            no warnings;
            $result = $1;
        }
        elsif ( m{(?<!\\) ([\$*]) (([\w\:\']*) \bVERSION)\b .* (?<![<>=!])\=[^=]}x ) {
			$result = $self->get_version($parsefile, $1, $2);
        }
        else {
          next;
        }
        last if defined $result;
    }
    close $fh;

    if ( defined $result && $result !~ /^v?[\d_\.]+$/ ) {
      require version;
      my $normal = eval { version->new( $result ) };
      $result = $normal if defined $normal;
    }
    if ( defined $result ) {
      $result = "undef" unless $result =~ m!^v?[\d_\.]+$!
                        or eval { version->parse( $result ) };
    }
    $result = "undef" unless defined $result;
    return $result;
}

sub get_version {
    my ($self, $parsefile, $sigil, $name) = @_;
    my $line = $_; # from the while() loop in parse_version
    {
        package ExtUtils::MakeMaker::_version;
        undef *version; # in case of unexpected version() sub
        eval {
            require version;
            version::->import;
        };
        no strict;
        no warnings;
        local *{$name};
        $line = $1 if $line =~ m{^(.+)}s;
        eval($line); ## no critic
        return ${$name};
    }
}

=item pasthru (o)

Defines the string that is passed to recursive make calls in
subdirectories. The variables like C<PASTHRU_DEFINE> are used in each
level, and passed downwards on the command-line with e.g. the value of
that level's DEFINE. Example:

    # Level 0 has DEFINE = -Dfunky
    # This code will define level 0's PASTHRU=PASTHRU_DEFINE="$(DEFINE)
    #     $(PASTHRU_DEFINE)"
    # Level 0's $(CCCMD) will include macros $(DEFINE) and $(PASTHRU_DEFINE)
    # So will level 1's, so when level 1 compiles, it will get right values
    # And so ad infinitum

=cut

sub pasthru {
    my($self) = shift;
    my(@m);

    my(@pasthru);
    my($sep) = $Is{VMS} ? ',' : '';
    $sep .= "\\\n\t";

    foreach my $key (qw(LIB LIBPERL_A LINKTYPE OPTIMIZE LD
                     PREFIX INSTALL_BASE)
                 )
    {
        next unless defined $self->{$key};
	push @pasthru, "$key=\"\$($key)\"";
    }

    foreach my $key (qw(DEFINE INC)) {
        # default to the make var
        my $val = qq{\$($key)};
        # expand within perl if given since need to use quote_literal
        # since INC might include space-protecting ""!
        chomp($val = $self->{$key}) if defined $self->{$key};
        $val .= " \$(PASTHRU_$key)";
        my $quoted = $self->quote_literal($val);
        push @pasthru, qq{PASTHRU_$key=$quoted};
    }

    push @m, "\nPASTHRU = ", join ($sep, @pasthru), "\n";
    join "", @m;
}

=item perl_script

Takes one argument, a file name, and returns the file name, if the
argument is likely to be a perl script. On MM_Unix this is true for
any ordinary, readable file.

=cut

sub perl_script {
    my($self,$file) = @_;
    return $file if -r $file && -f _;
    return;
}

=item perldepend (o)

Defines the dependency from all *.h files that come with the perl
distribution.

=cut

sub perldepend {
    my($self) = shift;
    my(@m);

    my $make_config = $self->cd('$(PERL_SRC)', '$(MAKE) lib/Config.pm');

    push @m, sprintf <<'MAKE_FRAG', $make_config if $self->{PERL_SRC};
# Check for unpropogated config.sh changes. Should never happen.
# We do NOT just update config.h because that is not sufficient.
# An out of date config.h is not fatal but complains loudly!
$(PERL_INCDEP)/config.h: $(PERL_SRC)/config.sh
	-$(NOECHO) $(ECHO) "Warning: $(PERL_INC)/config.h out of date with $(PERL_SRC)/config.sh"; $(FALSE)

$(PERL_ARCHLIB)/Config.pm: $(PERL_SRC)/config.sh
	$(NOECHO) $(ECHO) "Warning: $(PERL_ARCHLIB)/Config.pm may be out of date with $(PERL_SRC)/config.sh"
	%s
MAKE_FRAG

    return join "", @m unless $self->needs_linking;

    if ($self->{OBJECT}) {
        # Need to add an object file dependency on the perl headers.
        # this is very important for XS modules in perl.git development.
        push @m, $self->_perl_header_files_fragment("/"); # Directory separator between $(PERL_INC)/header.h
    }

    push @m, join(" ", sort values %{$self->{XS}})." : \$(XSUBPPDEPS)\n"  if %{$self->{XS}};

    return join "\n", @m;
}


=item pm_to_blib

Defines target that copies all files in the hash PM to their
destination and autosplits them. See L<ExtUtils::Install/DESCRIPTION>

=cut

sub pm_to_blib {
    my $self = shift;
    my($autodir) = $self->catdir('$(INST_LIB)','auto');
    my $r = q{
pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM)
};

    # VMS will swallow '' and PM_FILTER is often empty.  So use q[]
    my $pm_to_blib = $self->oneliner(<<CODE, ['-MExtUtils::Install']);
pm_to_blib({\@ARGV}, '$autodir', q[\$(PM_FILTER)], '\$(PERM_DIR)')
CODE

    my @cmds = $self->split_command($pm_to_blib,
                  map { ($self->quote_literal($_) => $self->quote_literal($self->{PM}->{$_})) } sort keys %{$self->{PM}});

    $r .= join '', map { "\t\$(NOECHO) $_\n" } @cmds;
    $r .= qq{\t\$(NOECHO) \$(TOUCH) pm_to_blib\n};

    return $r;
}

# transform dot-separated version string into comma-separated quadruple
# examples:  '1.2.3.4.5' => '1,2,3,4'
#            '1.2.3'     => '1,2,3,0'
sub _ppd_version {
    my ($self, $string) = @_;
    return join ',', ((split /\./, $string), (0) x 4)[0..3];
}

=item ppd

Defines target that creates a PPD (Perl Package Description) file
for a binary distribution.

=cut

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

    my $abstract = $self->{ABSTRACT} || '';
    $abstract =~ s/\n/\\n/sg;
    $abstract =~ s/</&lt;/g;
    $abstract =~ s/>/&gt;/g;

    my $author = join(', ',@{ ref $self->{AUTHOR} eq 'ARRAY' ? $self->{AUTHOR} : [ $self->{AUTHOR} || '']});
    $author =~ s/</&lt;/g;
    $author =~ s/>/&gt;/g;

    my $ppd_file = "$self->{DISTNAME}.ppd";

    my @ppd_chunks = qq(<SOFTPKG NAME="$self->{DISTNAME}" VERSION="$self->{VERSION}">\n);

    push @ppd_chunks, sprintf <<'PPD_HTML', $abstract, $author;
    <ABSTRACT>%s</ABSTRACT>
    <AUTHOR>%s</AUTHOR>
PPD_HTML

    push @ppd_chunks, "    <IMPLEMENTATION>\n";
    if ( $self->{MIN_PERL_VERSION} ) {
        my $min_perl_version = $self->_ppd_version($self->{MIN_PERL_VERSION});
        push @ppd_chunks, sprintf <<'PPD_PERLVERS', $min_perl_version;
        <PERLCORE VERSION="%s" />
PPD_PERLVERS

    }

    # Don't add "perl" to requires.  perl dependencies are
    # handles by ARCHITECTURE.
    my %prereqs = %{$self->{PREREQ_PM}};
    delete $prereqs{perl};

    # Build up REQUIRE
    foreach my $prereq (sort keys %prereqs) {
        my $name = $prereq;
        $name .= '::' unless $name =~ /::/;
        my $version = $prereqs{$prereq};

        my %attrs = ( NAME => $name );
        $attrs{VERSION} = $version if $version;
        my $attrs = join " ", map { qq[$_="$attrs{$_}"] } sort keys %attrs;
        push @ppd_chunks, qq(        <REQUIRE $attrs />\n);
    }

    my $archname = $Config{archname};

    # archname did not change from 5.6 to 5.8, but those versions may
    # not be not binary compatible so now we append the part of the
    # version that changes when binary compatibility may change
    if ("$]" >= 5.008) {
        $archname .= "-$Config{api_revision}.$Config{api_version}";
    }
    push @ppd_chunks, sprintf <<'PPD_OUT', $archname;
        <ARCHITECTURE NAME="%s" />
PPD_OUT

    if ($self->{PPM_INSTALL_SCRIPT}) {
        if ($self->{PPM_INSTALL_EXEC}) {
            push @ppd_chunks, sprintf qq{        <INSTALL EXEC="%s">%s</INSTALL>\n},
                  $self->{PPM_INSTALL_EXEC}, $self->{PPM_INSTALL_SCRIPT};
        }
        else {
            push @ppd_chunks, sprintf qq{        <INSTALL>%s</INSTALL>\n},
                  $self->{PPM_INSTALL_SCRIPT};
        }
    }

    if ($self->{PPM_UNINSTALL_SCRIPT}) {
        if ($self->{PPM_UNINSTALL_EXEC}) {
            push @ppd_chunks, sprintf qq{        <UNINSTALL EXEC="%s">%s</UNINSTALL>\n},
                  $self->{PPM_UNINSTALL_EXEC}, $self->{PPM_UNINSTALL_SCRIPT};
        }
        else {
            push @ppd_chunks, sprintf qq{        <UNINSTALL>%s</UNINSTALL>\n},
                  $self->{PPM_UNINSTALL_SCRIPT};
        }
    }

    my ($bin_location) = $self->{BINARY_LOCATION} || '';
    $bin_location =~ s/\\/\\\\/g;

    push @ppd_chunks, sprintf <<'PPD_XML', $bin_location;
        <CODEBASE HREF="%s" />
    </IMPLEMENTATION>
</SOFTPKG>
PPD_XML

    my @ppd_cmds = $self->stashmeta(join('', @ppd_chunks), $ppd_file);

    return sprintf <<'PPD_OUT', join "\n\t", @ppd_cmds;
# Creates a PPD (Perl Package Description) for a binary distribution.
ppd :
	%s
PPD_OUT

}

=item prefixify

  $MM->prefixify($var, $prefix, $new_prefix, $default);

Using either $MM->{uc $var} || $Config{lc $var}, it will attempt to
replace it's $prefix with a $new_prefix.

Should the $prefix fail to match I<AND> a PREFIX was given as an
argument to WriteMakefile() it will set it to the $new_prefix +
$default.  This is for systems whose file layouts don't neatly fit into
our ideas of prefixes.

This is for heuristics which attempt to create directory structures
that mirror those of the installed perl.

For example:

    $MM->prefixify('installman1dir', '/usr', '/home/foo', 'man/man1');

this will attempt to remove '/usr' from the front of the
$MM->{INSTALLMAN1DIR} path (initializing it to $Config{installman1dir}
if necessary) and replace it with '/home/foo'.  If this fails it will
simply use '/home/foo/man/man1'.

=cut

sub prefixify {
    my($self,$var,$sprefix,$rprefix,$default) = @_;

    my $path = $self->{uc $var} ||
               $Config_Override{lc $var} || $Config{lc $var} || '';

    $rprefix .= '/' if $sprefix =~ m|/$|;

    warn "  prefixify $var => $path\n" if $Verbose >= 2;
    warn "    from $sprefix to $rprefix\n" if $Verbose >= 2;

    if( $self->{ARGS}{PREFIX} &&
        $path !~ s{^\Q$sprefix\E\b}{$rprefix}s )
    {

        warn "    cannot prefix, using default.\n" if $Verbose >= 2;
        warn "    no default!\n" if !$default && $Verbose >= 2;

        $path = $self->catdir($rprefix, $default) if $default;
    }

    print "    now $path\n" if $Verbose >= 2;
    return $self->{uc $var} = $path;
}


=item processPL (o)

Defines targets to run *.PL files.

=cut

sub processPL {
    my $self = shift;
    my $pl_files = $self->{PL_FILES};

    return "" unless $pl_files;

    my $m = '';
    foreach my $plfile (sort keys %$pl_files) {
        my $targets = $pl_files->{$plfile};
        my $list =
            ref($targets) eq 'HASH'  ? [ sort keys %$targets ] :
            ref($targets) eq 'ARRAY' ? $pl_files->{$plfile}   :
            [$pl_files->{$plfile}];

        foreach my $target (@$list) {
            if( $Is{VMS} ) {
                $plfile = vmsify($self->eliminate_macros($plfile));
                $target = vmsify($self->eliminate_macros($target));
            }

            # Normally a .PL file runs AFTER pm_to_blib so it can have
            # blib in its @INC and load the just built modules.  BUT if
            # the generated module is something in $(TO_INST_PM) which
            # pm_to_blib depends on then it can't depend on pm_to_blib
            # else we have a dependency loop.
            my $pm_dep;
            my $perlrun;
            if( defined $self->{PM}{$target} ) {
                $pm_dep  = '';
                $perlrun = 'PERLRUN';
            }
            else {
                $pm_dep  = 'pm_to_blib';
                $perlrun = 'PERLRUNINST';
            }

            my $extra_inputs = '';
            if( ref($targets) eq 'HASH' ) {
                my $inputs = ref($targets->{$target})
                    ? $targets->{$target}
                    : [$targets->{$target}];

                for my $input (@$inputs) {
                    if( $Is{VMS} ) {
                        $input = vmsify($self->eliminate_macros($input));
                    }
                    $extra_inputs .= ' '.$input;
                }
            }

            $m .= <<MAKE_FRAG;

pure_all :: $target
	\$(NOECHO) \$(NOOP)

$target :: $plfile $pm_dep $extra_inputs
	\$($perlrun) $plfile $target $extra_inputs
MAKE_FRAG

        }
    }

    return $m;
}

=item specify_shell

Specify SHELL if needed - not done on Unix.

=cut

sub specify_shell {
  return '';
}

=item quote_paren

Backslashes parentheses C<()> in command line arguments.
Doesn't handle recursive Makefile C<$(...)> constructs,
but handles simple ones.

=cut

sub quote_paren {
    my $arg = shift;
    $arg =~ s{\$\((.+?)\)}{\$\\\\($1\\\\)}g;	# protect $(...)
    $arg =~ s{(?<!\\)([()])}{\\$1}g;		# quote unprotected
    $arg =~ s{\$\\\\\((.+?)\\\\\)}{\$($1)}g;	# unprotect $(...)
    return $arg;
}

=item replace_manpage_separator

  my $man_name = $MM->replace_manpage_separator($file_path);

Takes the name of a package, which may be a nested package, in the
form 'Foo/Bar.pm' and replaces the slash with C<::> or something else
safe for a man page file name.  Returns the replacement.

=cut

sub replace_manpage_separator {
    my($self,$man) = @_;

    $man =~ s,/+,::,g;
    return $man;
}


=item cd

=cut

sub cd {
    my($self, $dir, @cmds) = @_;

    # No leading tab and no trailing newline makes for easier embedding
    my $make_frag = join "\n\t", map { "cd $dir && $_" } @cmds;

    return $make_frag;
}

=item oneliner

=cut

sub oneliner {
    my($self, $cmd, $switches) = @_;
    $switches = [] unless defined $switches;

    # Strip leading and trailing newlines
    $cmd =~ s{^\n+}{};
    $cmd =~ s{\n+$}{};

    my @cmds = split /\n/, $cmd;
    $cmd = join " \n\t  -e ", map $self->quote_literal($_), @cmds;
    $cmd = $self->escape_newlines($cmd);

    $switches = join ' ', @$switches;

    return qq{\$(ABSPERLRUN) $switches -e $cmd --};
}


=item quote_literal

Quotes macro literal value suitable for being used on a command line so
that when expanded by make, will be received by command as given to
this method:

  my $quoted = $mm->quote_literal(q{it isn't});
  # returns:
  #   'it isn'\''t'
  print MAKEFILE "target:\n\techo $quoted\n";
  # when run "make target", will output:
  #   it isn't

=cut

sub quote_literal {
    my($self, $text, $opts) = @_;
    $opts->{allow_variables} = 1 unless defined $opts->{allow_variables};

    # Quote single quotes
    $text =~ s{'}{'\\''}g;

    $text = $opts->{allow_variables}
      ? $self->escape_dollarsigns($text) : $self->escape_all_dollarsigns($text);

    return "'$text'";
}


=item escape_newlines

=cut

sub escape_newlines {
    my($self, $text) = @_;

    $text =~ s{\n}{\\\n}g;

    return $text;
}


=item max_exec_len

Using L<POSIX>::ARG_MAX.  Otherwise falling back to 4096.

=cut

sub max_exec_len {
    my $self = shift;

    if (!defined $self->{_MAX_EXEC_LEN}) {
        if (my $arg_max = eval { require POSIX;  &POSIX::ARG_MAX }) {
            $self->{_MAX_EXEC_LEN} = $arg_max;
        }
        else {      # POSIX minimum exec size
            $self->{_MAX_EXEC_LEN} = 4096;
        }
    }

    return $self->{_MAX_EXEC_LEN};
}


=item static (o)

Defines the static target.

=cut

sub static {
# --- Static Loading Sections ---

    my($self) = shift;
    '
## $(INST_PM) has been moved to the all: target.
## It remains here for awhile to allow for old usage: "make static"
static :: $(FIRST_MAKEFILE) $(INST_STATIC)
	$(NOECHO) $(NOOP)
';
}

sub static_lib {
    my($self) = @_;
    return '' unless $self->has_link_code;
    my(@m);
    my @libs;
    if ($self->{XSMULTI}) {
	for my $ext ($self->_xs_list_basenames) {
	    my ($v, $d, $f) = File::Spec->splitpath($ext);
	    my @d = File::Spec->splitdir($d);
	    shift @d if $d[0] eq 'lib';
	    my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
	    my $instfile = $self->catfile($instdir, "$f\$(LIB_EXT)");
	    my $objfile = "$ext\$(OBJ_EXT)";
	    push @libs, [ $objfile, $instfile, $instdir ];
	}
    } else {
	@libs = ([ qw($(OBJECT) $(INST_STATIC) $(INST_ARCHAUTODIR)) ]);
    }
    push @m, map { $self->xs_make_static_lib(@$_); } @libs;
    join "\n", @m;
}

=item xs_make_static_lib

Defines the recipes for the C<static_lib> section.

=cut

sub xs_make_static_lib {
    my ($self, $from, $to, $todir) = @_;
    my @m = sprintf '%s: %s $(MYEXTLIB) %s$(DFSEP).exists'."\n", $to, $from, $todir;
    push @m, "\t\$(RM_F) \"\$\@\"\n";
    push @m, $self->static_lib_fixtures;
    push @m, $self->static_lib_pure_cmd($from);
    push @m, "\t\$(CHMOD) \$(PERM_RWX) \$\@\n";
    push @m, $self->static_lib_closures($todir);
    join '', @m;
}

=item static_lib_closures

Records C<$(EXTRALIBS)> in F<extralibs.ld> and F<$(PERL_SRC)/ext.libs>.

=cut

sub static_lib_closures {
    my ($self, $todir) = @_;
    my @m = sprintf <<'MAKE_FRAG', $todir;
	$(NOECHO) $(ECHO) "$(EXTRALIBS)" > %s$(DFSEP)extralibs.ld
MAKE_FRAG
    # Old mechanism - still available:
    push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS};
	$(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)$(DFSEP)ext.libs
MAKE_FRAG
    @m;
}

=item static_lib_fixtures

Handles copying C<$(MYEXTLIB)> as starter for final static library that
then gets added to.

=cut

sub static_lib_fixtures {
    my ($self) = @_;
    # If this extension has its own library (eg SDBM_File)
    # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
    return unless $self->{MYEXTLIB};
    "\t\$(CP) \$(MYEXTLIB) \"\$\@\"\n";
}

=item static_lib_pure_cmd

Defines how to run the archive utility.

=cut

sub static_lib_pure_cmd {
    my ($self, $from) = @_;
    my $ar;
    if (exists $self->{FULL_AR} && -x $self->{FULL_AR}) {
        # Prefer the absolute pathed ar if available so that PATH
        # doesn't confuse us.  Perl itself is built with the full_ar.
        $ar = 'FULL_AR';
    } else {
        $ar = 'AR';
    }
    sprintf <<'MAKE_FRAG', $ar, $from;
	$(%s) $(AR_STATIC_ARGS) "$@" %s
	$(RANLIB) "$@"
MAKE_FRAG
}

=item staticmake (o)

Calls makeaperl.

=cut

sub staticmake {
    my($self, %attribs) = @_;
    my(@static);

    my(@searchdirs)=($self->{PERL_ARCHLIB}, $self->{SITEARCHEXP},  $self->{INST_ARCHLIB});

    # And as it's not yet built, we add the current extension
    # but only if it has some C code (or XS code, which implies C code)
    if (@{$self->{C}}) {
	@static = $self->catfile($self->{INST_ARCHLIB},
				 "auto",
				 $self->{FULLEXT},
				 "$self->{BASEEXT}$self->{LIB_EXT}"
				);
    }

    # Either we determine now, which libraries we will produce in the
    # subdirectories or we do it at runtime of the make.

    # We could ask all subdir objects, but I cannot imagine, why it
    # would be necessary.

    # Instead we determine all libraries for the new perl at
    # runtime.
    my(@perlinc) = ($self->{INST_ARCHLIB}, $self->{INST_LIB}, $self->{PERL_ARCHLIB}, $self->{PERL_LIB});

    $self->makeaperl(MAKE	=> $self->{MAKEFILE},
		     DIRS	=> \@searchdirs,
		     STAT	=> \@static,
		     INCL	=> \@perlinc,
		     TARGET	=> $self->{MAP_TARGET},
		     TMP	=> "",
		     LIBPERL	=> $self->{LIBPERL_A}
		    );
}

=item subdir_x (o)

Helper subroutine for subdirs

=cut

sub subdir_x {
    my($self, $subdir) = @_;

    my $subdir_cmd = $self->cd($subdir,
      '$(MAKE) $(USEMAKEFILE) $(FIRST_MAKEFILE) all $(PASTHRU)'
    );
    return sprintf <<'EOT', $subdir_cmd;

subdirs ::
	$(NOECHO) %s
EOT

}

=item subdirs (o)

Defines targets to process subdirectories.

=cut

sub subdirs {
# --- Sub-directory Sections ---
    my($self) = shift;
    my(@m);
    # This method provides a mechanism to automatically deal with
    # subdirectories containing further Makefile.PL scripts.
    # It calls the subdir_x() method for each subdirectory.
    foreach my $dir (@{$self->{DIR}}){
	push @m, $self->subdir_x($dir);
####	print "Including $dir subdirectory\n";
    }
    if (@m){
	unshift @m, <<'EOF';

# The default clean, realclean and test targets in this Makefile
# have automatically been given entries for each subdir.

EOF
    } else {
	push(@m, "\n# none")
    }
    join('',@m);
}

=item test (o)

Defines the test targets.

=cut

sub test {
    my($self, %attribs) = @_;
    my $tests = $attribs{TESTS} || '';
    if (!$tests && -d 't' && defined $attribs{RECURSIVE_TEST_FILES}) {
        $tests = $self->find_tests_recursive;
    }
    elsif (!$tests && -d 't') {
        $tests = $self->find_tests;
    }
    # have to do this because nmake is broken
    $tests =~ s!/!\\!g if $self->is_make_type('nmake');
    # note: 'test.pl' name is also hardcoded in init_dirscan()
    my @m;
    my $default_testtype = $Config{usedl} ? 'dynamic' : 'static';
    push @m, <<EOF;
TEST_VERBOSE=0
TEST_TYPE=test_\$(LINKTYPE)
TEST_FILE = test.pl
TEST_FILES = $tests
TESTDB_SW = -d

testdb :: testdb_\$(LINKTYPE)
	\$(NOECHO) \$(NOOP)

test :: \$(TEST_TYPE)
	\$(NOECHO) \$(NOOP)

# Occasionally we may face this degenerate target:
test_ : test_$default_testtype
	\$(NOECHO) \$(NOOP)

EOF

    for my $linktype (qw(dynamic static)) {
        my $directdeps = join ' ', grep !$self->{SKIPHASH}{$_}, $linktype, "pure_all"; # no depend on a linktype if SKIPped
        push @m, "subdirs-test_$linktype :: $directdeps\n";
        foreach my $dir (@{ $self->{DIR} }) {
            my $test = $self->cd($dir, "\$(MAKE) test_$linktype \$(PASTHRU)");
            push @m, "\t\$(NOECHO) $test\n";
        }
        push @m, "\n";
        if ($tests or -f "test.pl") {
            for my $testspec ([ '', '' ], [ 'db', ' $(TESTDB_SW)' ]) {
                my ($db, $switch) = @$testspec;
                my ($command, $deps);
                # if testdb, build all but don't test all
                $deps = $db eq 'db' ? $directdeps : "subdirs-test_$linktype";
                if ($linktype eq 'static' and $self->needs_linking) {
                    my $target = File::Spec->rel2abs('$(MAP_TARGET)');
                    $command = qq{"$target" \$(MAP_PERLINC)};
                    $deps .= ' $(MAP_TARGET)';
                } else {
                    $command = '$(FULLPERLRUN)' . $switch;
                }
                push @m, "test${db}_$linktype :: $deps\n";
                if ($db eq 'db') {
                    push @m, $self->test_via_script($command, '$(TEST_FILE)')
                } else {
                    push @m, $self->test_via_script($command, '$(TEST_FILE)')
                        if -f "test.pl";
                    push @m, $self->test_via_harness($command, '$(TEST_FILES)')
                        if $tests;
                }
                push @m, "\n";
            }
        } else {
            push @m, _sprintf562 <<'EOF', $linktype;
testdb_%1$s test_%1$s :: subdirs-test_%1$s
	$(NOECHO) $(ECHO) 'No tests defined for $(NAME) extension.'

EOF
        }
    }

    join "", @m;
}

=item test_via_harness (override)

For some reason which I forget, Unix machines like to have
PERL_DL_NONLAZY set for tests.

=cut

sub test_via_harness {
    my($self, $perl, $tests) = @_;
    return $self->SUPER::test_via_harness("PERL_DL_NONLAZY=1 $perl", $tests);
}

=item test_via_script (override)

Again, the PERL_DL_NONLAZY thing.

=cut

sub test_via_script {
    my($self, $perl, $script) = @_;
    return $self->SUPER::test_via_script("PERL_DL_NONLAZY=1 $perl", $script);
}


=item tool_xsubpp (o)

Determines typemaps, xsubpp version, prototype behaviour.

=cut

sub tool_xsubpp {
    my($self) = shift;
    return "" unless $self->needs_linking;

    my $xsdir;
    my @xsubpp_dirs = @INC;

    # Make sure we pick up the new xsubpp if we're building perl.
    unshift @xsubpp_dirs, $self->{PERL_LIB} if $self->{PERL_CORE};

    my $foundxsubpp = 0;
    foreach my $dir (@xsubpp_dirs) {
        $xsdir = $self->catdir($dir, 'ExtUtils');
        if( -r $self->catfile($xsdir, "xsubpp") ) {
            $foundxsubpp = 1;
            last;
        }
    }
    die "ExtUtils::MM_Unix::tool_xsubpp : Can't find xsubpp" if !$foundxsubpp;

    my $tmdir   = $self->catdir($self->{PERL_LIB},"ExtUtils");
    my(@tmdeps) = $self->catfile($tmdir,'typemap');
    if( $self->{TYPEMAPS} ){
        foreach my $typemap (@{$self->{TYPEMAPS}}){
            if( ! -f  $typemap ) {
                warn "Typemap $typemap not found.\n";
            }
            else {
                $typemap = vmsify($typemap) if $Is{VMS};
                push(@tmdeps, $typemap);
            }
        }
    }
    push(@tmdeps, "typemap") if -f "typemap";
    # absolutised because with deep-located typemaps, eg "lib/XS/typemap",
    # if xsubpp is called from top level with
    #     $(XSUBPP) ... -typemap "lib/XS/typemap" "lib/XS/Test.xs"
    # it says:
    #     Can't find lib/XS/type map in (fulldir)/lib/XS
    # because ExtUtils::ParseXS::process_file chdir's to .xs file's
    # location. This is the only way to get all specified typemaps used,
    # wherever located.
    my @tmargs = map { '-typemap '.$self->quote_literal(File::Spec->rel2abs($_)) } @tmdeps;
    $_ = $self->quote_dep($_) for @tmdeps;
    if( exists $self->{XSOPT} ){
        unshift( @tmargs, $self->{XSOPT} );
    }

    if ($Is{VMS}                          &&
        $Config{'ldflags'}               &&
        $Config{'ldflags'} =~ m!/Debug!i &&
        (!exists($self->{XSOPT}) || $self->{XSOPT} !~ /linenumbers/)
       )
    {
        unshift(@tmargs,'-nolinenumbers');
    }


    $self->{XSPROTOARG} = "" unless defined $self->{XSPROTOARG};
    my $xsdirdep = $self->quote_dep($xsdir);
    # -dep for use when dependency not command

    return qq{
XSUBPPDIR = $xsdir
XSUBPP = "\$(XSUBPPDIR)\$(DFSEP)xsubpp"
XSUBPPRUN = \$(PERLRUN) \$(XSUBPP)
XSPROTOARG = $self->{XSPROTOARG}
XSUBPPDEPS = @tmdeps $xsdirdep\$(DFSEP)xsubpp
XSUBPPARGS = @tmargs
XSUBPP_EXTRA_ARGS =
};
}


=item all_target

Build man pages, too

=cut

sub all_target {
    my $self = shift;

    return <<'MAKE_EXT';
all :: pure_all manifypods
	$(NOECHO) $(NOOP)
MAKE_EXT
}

=item top_targets (o)

Defines the targets all, subdirs, config, and O_FILES

=cut

sub top_targets {
# --- Target Sections ---

    my($self) = shift;
    my(@m);

    push @m, $self->all_target, "\n" unless $self->{SKIPHASH}{'all'};

    push @m, sprintf <<'EOF';
pure_all :: config pm_to_blib subdirs linkext
	$(NOECHO) $(NOOP)

subdirs :: $(MYEXTLIB)
	$(NOECHO) $(NOOP)

config :: $(FIRST_MAKEFILE) blibdirs
	$(NOECHO) $(NOOP)
EOF

    push @m, '
$(O_FILES) : $(H_FILES)
' if @{$self->{O_FILES} || []} && @{$self->{H} || []};

    push @m, q{
help :
	perldoc ExtUtils::MakeMaker
};

    join('',@m);
}

=item writedoc

Obsolete, deprecated method. Not used since Version 5.21.

=cut

sub writedoc {
# --- perllocal.pod section ---
    my($self,$what,$name,@attribs)=@_;
    my $time = gmtime($ENV{SOURCE_DATE_EPOCH} || time);
    print "=head2 $time: $what C<$name>\n\n=over 4\n\n=item *\n\n";
    print join "\n\n=item *\n\n", map("C<$_>",@attribs);
    print "\n\n=back\n\n";
}

=item xs_c (o)

Defines the suffix rules to compile XS files to C.

=cut

sub xs_c {
    my($self) = shift;
    return '' unless $self->needs_linking();
    '
.xs.c:
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc
	$(MV) $*.xsc $*.c
';
}

=item xs_cpp (o)

Defines the suffix rules to compile XS files to C++.

=cut

sub xs_cpp {
    my($self) = shift;
    return '' unless $self->needs_linking();
    '
.xs.cpp:
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
	$(MV) $*.xsc $*.cpp
';
}

=item xs_o (o)

Defines suffix rules to go from XS to object files directly. This was
originally only intended for broken make implementations, but is now
necessary for per-XS file under C<XSMULTI>, since each XS file might
have an individual C<$(VERSION)>.

=cut

sub xs_o {
    my ($self) = @_;
    return '' unless $self->needs_linking();
    my $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*$(OBJ_EXT)') : '';
    my $dbgout = $self->dbgoutflag;
    $dbgout = $dbgout ? "$dbgout " : '';
    my $frag = '';
    # dmake makes noise about ambiguous rule
    $frag .= sprintf <<'EOF', $dbgout, $m_o unless $self->is_make_type('dmake');
.xs$(OBJ_EXT) :
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
	$(MV) $*.xsc $*.c
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) %s$*.c %s
EOF
    if ($self->{XSMULTI}) {
	for my $ext ($self->_xs_list_basenames) {
	    my $pmfile = "$ext.pm";
	    croak "$ext.xs has no matching $pmfile: $!" unless -f $pmfile;
	    my $version = $self->parse_version($pmfile);
	    my $cccmd = $self->{CONST_CCCMD};
	    $cccmd =~ s/^\s*CCCMD\s*=\s*//;
	    $cccmd =~ s/\$\(DEFINE_VERSION\)/-DVERSION=\\"$version\\"/;
	    $cccmd =~ s/\$\(XS_DEFINE_VERSION\)/-DXS_VERSION=\\"$version\\"/;
            $self->_xsbuild_replace_macro($cccmd, 'xs', $ext, 'INC');
            my $define = '$(DEFINE)';
            $self->_xsbuild_replace_macro($define, 'xs', $ext, 'DEFINE');
            #                             1     2       3     4        5
            $frag .= _sprintf562 <<'EOF', $ext, $cccmd, $m_o, $define, $dbgout;

%1$s$(OBJ_EXT): %1$s.xs
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
	$(MV) $*.xsc $*.c
	%2$s $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) %4$s %5$s$*.c %3$s
EOF
	}
    }
    $frag =~ s/"-I(\$\(PERL_INC\))"/-iwithsysroot "$1"/sg if $Is{ApplCor};
    $frag;
}

# param gets modified
sub _xsbuild_replace_macro {
    my ($self, undef, $xstype, $ext, $varname) = @_;
    my $value = $self->_xsbuild_value($xstype, $ext, $varname);
    return unless defined $value;
    $_[1] =~ s/\$\($varname\)/$value/;
}

sub _xsbuild_value {
    my ($self, $xstype, $ext, $varname) = @_;
    return $self->{XSBUILD}{$xstype}{$ext}{$varname}
        if $self->{XSBUILD}{$xstype}{$ext}{$varname};
    return $self->{XSBUILD}{$xstype}{all}{$varname}
        if $self->{XSBUILD}{$xstype}{all}{$varname};
    ();
}

1;

=back

=head1 SEE ALSO

L<ExtUtils::MakeMaker>

=cut

__END__
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              nstall" depois de reinicializar para resolver dependências.
Extended_description-ro.utf-8: Această versiune a bibliotecii libc GNU necesită versiunea nucleului ${kernel_ver} sau o versiune ulterioară.  Actualizați nucleul și să reporniți înainte de a instala glibc. Este posibil să fie nevoie să utilizați comanda «apt -f install» după repornire, pentru a rezolva problemele de dependențe.
Extended_description-sk.utf-8: Táto verzia GNU libc vyžaduje verziu kernelu ${kernel_ver} alebo neskoršiu. Aktualizujte prosím Váš kernel a reštartujte systém pred inštaláciou glibc. V prípade chýbajúcich závislostí po reštarte, použite príkaz "apt -f install".
Extended_description-tr.utf-8: GNU libc kitaplığının bu sürümü ${kernel_ver} çekirdek sürümü ya da daha yenisi ile çalışabilmektedir. GNU libc kurulumu öncesinde çekirdek sürümünüzü güncelleyin ve sisteminizi yeniden başlatın. Bağımlılık sorunlarını gidermek için, yeniden başlatmanız sonrasında "apt -f install" komutunu kullanmanız gerekebilir.
Extended_description-zh_cn.utf-8: 此版本的 GNU glibc 需要版本为 ${kernel_ver} 或更高版本的内核。安装 glibc 前请先升级你的内核并重启计算机。重启后你可能需要使用 "apt -f install" 来解决依赖问题。
Type: error

Name: glibc/restart-failed
Description: Failure restarting some services for GNU libc upgrade
Description-ar.utf-8: فشلت عملية إعادة تشغيل بعض الخدمات لترقية GNU libc
Description-ca.utf-8: No s'ha pogut reiniciar alguns serveis per a l'actualització de GNU libc
Description-cs.utf-8: Chyba při restartu některých služeb během aktualizace GNU libc
Description-da.utf-8: Kunne ikke genstarte udvalgte tjenester for GNU libc-opgraderingen
Description-de.utf-8: Fehler beim Neustarten einiger Dienste für das GNU Libc-Upgrade
Description-el.utf-8: Αποτυχία επανεκκίνησης κάποιων υπηρεσιών για την αναβάθμιση του GNU libc
Description-es.utf-8: Fallo al reiniciar algunos servicios para la actualización de la biblioteca libc de GNU
Description-eu.utf-8: Huts GNU glibc bertsio berritzerkoan zenbait zerbitzu berrabiaraztean
Description-fi.utf-8: Joidenkin palveluiden käynnistys epäonnistui päivitettäessä GNU libc:tä
Description-fr.utf-8: Échec du redémarrage de certains services lors de la mise à niveau de GNU libc
Description-gl.utf-8: Problemas ao reiniciar algúns servizos para a actualización de GNU libc
Description-hu.utf-8: Nem sikerült újraindítani némelyik szolgáltatást a GNU libc frissítésekor
Description-it.utf-8: Errore nel riavvio di alcuni servizi per l'aggiornamento di GNU libc
Description-ja.utf-8: GNU libc 更新のためのいくつかのサービスの再起動で失敗
Description-ko.utf-8: GNU libc 업그레이드로 인한 서비스 다시 시작에 실패
Description-lt.utf-8: Nepavyko paleisti iš naujo kai kurių tarnybų atnaujinus GNU libc
Description-nb.utf-8: Noen tjenester kunne ikke restartes for GNU libc-oppgradering
Description-nl.utf-8: Herstarten van sommige diensten bij de opwaardering van GNU libc is mislukt.
Description-no.utf-8: Noen tjenester kunne ikke restartes for GNU libc-oppgradering
Description-pl.utf-8: Nastąpił błąd podczas restartowania niektórych usług po aktualizacji GNU libc
Description-pt.utf-8: Falha ao reiniciar alguns serviços para a actualização da GNU libc
Description-pt_br.utf-8: Falha ao reiniciar alguns serviços para atualização da GNU libc
Description-ro.utf-8: Eșec la repornirea unor servicii pentru înnoirea GNU libc
Description-ru.utf-8: Произошёл сбой при перезапуске некоторых служб для обновления GNU libc
Description-sk.utf-8: Nepodarilo sa reštartovať niektoré služby pri aktualizácii GNU libc
Description-sv.utf-8: Misslyckades med att starta om vissa tjänster för uppgraderingen av GNU libc
Description-tr.utf-8: GNU libc kitaplığının yükseltmesi sırasında bazı hizmetler yeniden başlatılamadı
Description-vi.utf-8: Lỗi khởi chạy lại một số dịch vụ để nâng cấp libc GNU.
Description-zh_cn.utf-8: 因 GNU libc 升级而重启的部分服务重启失败
Extended_description: The following services could not be restarted for the GNU libc library upgrade:\n\n${services}\n\nYou will need to start these manually by running 'invoke-rc.d <service> start'.
Extended_description-ar.utf-8: تعذر إعادة تشغيل الخدمات التالية لترقية مكتبة GNU libc:\n\n${services}\n\nعليك بتشغيل هذه الخدمات يدوياً بتنفيذ الأمر 'invoke-rc.d <service> start'.
Extended_description-ca.utf-8: No s'ha pogut reiniciar els serveis següents per a l'actualització de la biblioteca GNU libc:\n\n${services}\n\nHaureu d'iniciar aquests serveis manualment executant «invoke-rc.d <servei> start».
Extended_description-cs.utf-8: Následující služby nemohly být během aktualizace knihovny GNU libc restartovány:\n\n${services}\n\nBudete je muset spustit ručně příkazem „invoke-rc.d <služba> start“.
Extended_description-da.utf-8: De følgende tjenester kunne ikke genstartes for GNU libc-biblioteksopgraderingen:\n\n${services}\n\nDu skal genstarte disse manuelt ved at køre »invoke-rc.d <service> start«.
Extended_description-de.utf-8: Die folgenden Dienste konnten für das GNU Libc-Upgrade nicht neu gestartet werden:\n\n${services}\n\nSie müssen diese manuell starten, indem Sie »invoke-rc.d <service> start« ausführen.
Extended_description-el.utf-8: Οι ακόλουθες υπηρεσίες δεν μπορούσαν να επανεκκινηθούν για την αναβάθμιση της βιβλιοθήκης GNU libc:\n\n${services}\n\nΘα χρειαστεί να τις εκκινήστε χειροκίνητα τρέχοντας 'invoke-rc.d <service> start'.
Extended_description-es.utf-8: Los siguientes servicios no se pudieron reiniciar para la actualización de la biblioteca libc de GNU:\n\n${services}\n\nTendrá que iniciarlos manualmente ejecutando «invoke-rc.d <servicio> start».
Extended_description-eu.utf-8: Hurrengo zerbitzuak ezin izan dira berrabiarazi GNU glibc liburutegi bertsio berritzerako:\n\n${services}\n\nHauek eskuz abiarazi beharko dituzu 'invoke-rc.d <zerbitzua> start' eginaz.
Extended_description-fi.utf-8: Seuraavia palveluita ei voitu käynnistää uudelleen päivitettäessä GNU libc -kirjastoa:\n\n${services}\n\nNämä palvelut tulee käynnistää käsin ajamalla ”invoke-rc.d <palvelu> start”.
Extended_description-fr.utf-8: Les services suivants n'ont pas pu être redémarrés lors de la mise à niveau de la bibliothèque C de GNU :\n\n${services}\n\nIl est nécessaire de les redémarrer vous-même avec la commande « invoke-rc.d <service> start ».
Extended_description-gl.utf-8: Non se puido reiniciar os seguintes servizos para a actualización da biblioteca GNU libc:\n\n${services}\n\nHa ter que reinicialos manualmente executando "invoke-rc.d <servizo> start".
Extended_description-hu.utf-8: A következő szolgáltatásokat nem sikerült újraindítania GNU libc frissítésekor:\n\n${services}\n\nEzeket neked kell újraindítanod a 'invoke-rc.d <service> start' parancs futtatásával.
Extended_description-it.utf-8: Non è stato possibile riavviare i seguenti servizi per l'aggiornamento della libreria GNU libc:\n\n${services}\n\nÈ necessario avviarli manualmente con «invoke-rc.d <servizio> start».
Extended_description-ja.utf-8: GNU libc ライブラリ更新のための、以下のサービスの再起動ができませんでした。\n\n${services}\n\n'invoke-rc.d <サービス> start' を実行することで、これらを手動で起動する必要があります。
Extended_description-ko.utf-8: 다음 서비스들은 GNU libc 라이브러리 업그레이드로 인한 다시 시작에 실패하였습니다:\n\n${services}\n\n이 서비스들은 'invoke-rc.d <service> start'로 직접 다시 시작시키셔야 합니다.
Extended_description-lt.utf-8: Atnaujinus GNU libc nepavyko iš naujo paleisti šių procesų:\n\n${services}\n\nJas reikės paleisti rankiniu būdu įvykdant „invoke-rc.d tarnyba start“.
Extended_description-nb.utf-8: Følgende tjenester kunne ikke restartes for oppgradering av GNU libc-biblioteket:\n\n${services}\n\nDu må starte disse manuelt ved å kjøre «invoke-rc.d <service> start».
Extended_description-nl.utf-8: De volgende diensten konden niet herstart worden na de opwaardering van GNU libc:\n\n${services}\n\nU dient deze diensten handmatig te herstarten via het commando 'invoke-rc.d <dienst> start'.
Extended_description-no.utf-8: Følgende tjenester kunne ikke restartes for oppgradering av GNU libc-biblioteket:\n\n${services}\n\nDu må starte disse manuelt ved å kjøre «invoke-rc.d <service> start».
Extended_description-pl.utf-8: Następujące usługi nie zostały zrestartowane po aktualizacji GNU libc:\n\n${services}\n\nAby zrestartować te usługi ręcznie należy wywołać "invoke-rc.d <service> start".
Extended_description-pt.utf-8: Os seguintes serviços não puderam ser reiniciados para a actualização da biblioteca GNU libc:\n\n${services}\n\nTerá de os inicializar manualmente correndo 'invoke-rc.d <serviço> start'.
Extended_description-pt_br.utf-8: Os seguintes serviços não puderam ser reiniciados para a atualização da biblioteca GNU libc:\n\n${services}\n\nVocê deverá iniciá-los manualmente executando "invoke-rc.d <serviço> start".
Extended_description-ro.utf-8: Următoarele servicii nu ar trebui repornite la înnoirea bibliotecii GNU libc:\n\n${services}\n\nVa trebui să porniți aceste servicii manual executând comanda «invoke-rc.d <serviciul_dorit> start».
Extended_description-ru.utf-8: Следующие службы не могут быть перезапущены для обновления библиотеки GNU libc:\n\n${services}\n\nВам будет нужно запустить их вручную, для чего следует выполнить 'invoke-rc.d <service> start'.
Extended_description-sk.utf-8: Nasledovné služby sa pri aktualizácii knižnice GNU libc nepodarilo sa reštartovať:\n\n${services}\n\nBudete musieť tieto služby spustiť ručne pomocou „invoke-rc.d <service> start“.
Extended_description-sv.utf-8: Följande tjänster kunde inte startas om för uppgraderingen av GNU libc-biblioteket:\n\n${services}\n\nDu behöver starta dessa manuellt genom att köra "invoke-rc.d <tjänst> start".
Extended_description-tr.utf-8: Aşağıdaki hizmetler glibc yükseltmesi için yeniden başlatılamadı:\n\n${services}\n\nBu hizmetleri "invoke-rc.d <hizmet> start" komutunu kullanarak elle başlatmanız gerekecektedir.
Extended_description-vi.utf-8: Những dịch vụ theo đây không thể được khởi chạy lại để nâng cấp thư viện libc GNU:\n\n${services}\n\nBạn sẽ cần phải tự khởi chạy lại các dịch vụ này, bằng cách chạy lệnh « /etc/init.d/<service> start ».
Extended_description-zh_cn.utf-8: GNU libc 库升级，但下列服务无法重启：\n\n${services}\n\n你需要通过手动运行 'invoke-rc.d <service> start' 来启动这些服务。
Type: error

Name: glibc/restart-services
Description: Services to restart for GNU libc library upgrade:
Description-ar.utf-8: الخدمات المطلوب إعادة تشغيلها لتريقة مكتبة GNU libc:
Description-ca.utf-8: Serveis a reiniciar per l'actualització de la biblioteca GNU libc:
Description-cs.utf-8: Služby, které se mají restartovat po aktualizaci knihovny GNU libc:
Description-da.utf-8: Tjenester til genstart for GNU libc-biblioteksopgradering:
Description-de.utf-8: Dienste, die beim GNU Libc-Bibliotheks-Upgrade neu gestartet werden sollen:
Description-el.utf-8: Υπηρεσίες προς επανεκκίνηση, για την αναβάθμιση της βιβλιοθήκης GNU libc:
Description-es.utf-8: Servicios a reiniciar para la actualización de la biblioteca libc de GNU:
Description-eu.utf-8: GNU libc liburutegi eguneraketan berrabiarazi behar diren zerbitzuak:
Description-fi.utf-8: Palvelut, jotka tulee käynnistää uudelleen GNU libc -kirjastoa päivitettäessä:
Description-fr.utf-8: Services à redémarrer lors de la mise à niveau de la bibliothèque C de GNU :
Description-gl.utf-8: Servizos a reiniciar para a actualización da biblioteca GNU libc:
Description-hu.utf-8: A GNU libc könyvtár frissítéséhez újraindítandó szolgáltatások:
Description-it.utf-8: Servizi da riavviare per l'aggiornamento della libreria GNU libc:
Description-ja.utf-8: GNU libc ライブラリの更新で再起動するサービス:
Description-ko.utf-8: GNU libc 라이브러리 업그레이드로 인해 다시 시작시킬 서비스 목록:
Description-lt.utf-8: Tarnybos, kurias reikia paleisti iš naujo po GNU libc bibliotekos atnaujinimo:
Description-nb.utf-8: Tjenester som skal restartes for oppgradering av GNU libc-biblioteket:
Description-nl.utf-8: Omwille van de opwaardering van 'GNU libc' te herstarten diensten:
Description-no.utf-8: Tjenester som skal restartes for oppgradering av GNU libc-biblioteket:
Description-pl.utf-8: Usługi wymagające restartu po aktualizacji GNU libc:
Description-pt.utf-8: Serviços a reiniciar para a actualização da biblioteca GNU libc:
Description-pt_br.utf-8: Serviços a serem reiniciados para atualização da biblioteca GNU libc:
Description-ro.utf-8: Servicii ce trebuiesc repornite la înnoirea bibliotecii GNU libc:
Description-ru.utf-8: Для обновления GNU libc должны быть перезапущены следующие службы:
Description-sk.utf-8: Služby, ktoré sa majú po aktualizácii knižnice GNU libc reštartovať:
Description-sv.utf-8: Tjänster att starta om för uppgradering av GNU libc-biblioteket:
Description-tr.utf-8: GNU libc kitaplığının yükseltmesi için yeniden başlatılacak olan hizmetler:
Description-vi.utf-8: Các dịch vụ cần khởi chạy lại để nâng cấp thư viện libc GNU:
Description-zh_cn.utf-8: GNU libc 库升级需要重启如下的服务：
Extended_description: Running services and programs that are using NSS need to be restarted, otherwise they might not be able to do lookup or authentication any more (for services such as ssh, this can affect your ability to login). Please review the following space-separated list of init.d scripts for services to be restarted now, and correct it if needed.\n\nNote: restarting sshd/telnetd should not affect any existing connections.
Extended_description-ar.utf-8: هناك بعض الخدمات والبرامج التي تستخدم NSS يجب إعادة تشغيلها، وإلا لن تستطيع تلك الخدمات البحث أو المصادقة بعد الآن. تستطيع عملية التثبيت إعادة تشغيل بعض الخدمات (مثل  ssh والتي قد تؤثر على قدرتك الدخول). الرجاء مراجعة قائمة برامج init.d هذه بالخدمات التي يجب إعادة تشغيلها الآن، وصححها إن كنت بحاجة إلى ذلك.\n\nملاحظة: إعادة تشغيل sshd/telnetd يجب أن لايؤثر على أية اتصالات جارية.
Extended_description-ca.utf-8: És necessari tornar a iniciar els serveis i programes que utilitzen NSS, ja que si no es fa això podrien deixar de poder fer cerques o autenticacions (per a serveis com l'ssh, això pot afectar la vostra capacitat per a entrar al sistema). Comproveu la següent llista separada per comes de scripts d'init.d amb serveis que s'han de tornar a iniciar ara, i corregiu-la si és necessari.\n\nNota: reiniciar l'ssh/telnetd no hauria d'afectar cap connexió existent.
Extended_description-cs.utf-8: Běžící služby a programy využívající NSS se musí restartovat, protože jinak se může stát, že nebudou moci vyhledávat v systémových databázích nebo ověřovat uživatele. (U služeb typu ssh to může ovlivnit možnost přihlášení se.) Zkontrolujte prosím následující mezerami oddělený seznam služeb, které se mají restartovat a v případě potřeby jej opravte. Služby jsou v seznamu zastoupeny svýmpackage ExtUtils::MM_VMS;

use strict;
use warnings;

use ExtUtils::MakeMaker::Config;
require Exporter;

BEGIN {
    # so we can compile the thing on non-VMS platforms.
    if( $^O eq 'VMS' ) {
        require VMS::Filespec;
        VMS::Filespec->import;
    }
}

use File::Basename;

our $VERSION = '7.64';
$VERSION =~ tr/_//d;

require ExtUtils::MM_Any;
require ExtUtils::MM_Unix;
our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );

use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
our $Revision = $ExtUtils::MakeMaker::Revision;


=head1 NAME

ExtUtils::MM_VMS - methods to override UN*X behaviour in ExtUtils::MakeMaker

=head1 SYNOPSIS

  Do not use this directly.
  Instead, use ExtUtils::MM and it will figure out which MM_*
  class to use for you.

=head1 DESCRIPTION

See L<ExtUtils::MM_Unix> for a documentation of the methods provided
there. This package overrides the implementation of these methods, not
the semantics.

=head2 Methods always loaded

=over 4

=item wraplist

Converts a list into a string wrapped at approximately 80 columns.

=cut

sub wraplist {
    my($self) = shift;
    my($line,$hlen) = ('',0);

    foreach my $word (@_) {
      # Perl bug -- seems to occasionally insert extra elements when
      # traversing array (scalar(@array) doesn't show them, but
      # foreach(@array) does) (5.00307)
      next unless $word =~ /\w/;
      $line .= ' ' if length($line);
      if ($hlen > 80) { $line .= "\\\n\t"; $hlen = 0; }
      $line .= $word;
      $hlen += length($word) + 2;
    }
    $line;
}


# This isn't really an override.  It's just here because ExtUtils::MM_VMS
# appears in @MM::ISA before ExtUtils::Liblist::Kid, so if there isn't an ext()
# in MM_VMS, then AUTOLOAD is called, and bad things happen.  So, we just
# mimic inheritance here and hand off to ExtUtils::Liblist::Kid.
# XXX This hackery will die soon. --Schwern
sub ext {
    require ExtUtils::Liblist::Kid;
    goto &ExtUtils::Liblist::Kid::ext;
}

=back

=head2 Methods

Those methods which override default MM_Unix methods are marked
"(override)", while methods unique to MM_VMS are marked "(specific)".
For overridden methods, documentation is limited to an explanation
of why this method overrides the MM_Unix method; see the L<ExtUtils::MM_Unix>
documentation for more details.

=over 4

=item guess_name (override)

Try to determine name of extension being built.  We begin with the name
of the current directory.  Since VMS filenames are case-insensitive,
however, we look for a F<.pm> file whose name matches that of the current
directory (presumably the 'main' F<.pm> file for this extension), and try
to find a C<package> statement from which to obtain the Mixed::Case
package name.

=cut

sub guess_name {
    my($self) = @_;
    my($defname,$defpm,@pm,%xs);
    local *PM;

    $defname = basename(fileify($ENV{'DEFAULT'}));
    $defname =~ s![\d\-_]*\.dir.*$!!;  # Clip off .dir;1 suffix, and package version
    $defpm = $defname;
    # Fallback in case for some reason a user has copied the files for an
    # extension into a working directory whose name doesn't reflect the
    # extension's name.  We'll use the name of a unique .pm file, or the
    # first .pm file with a matching .xs file.
    if (not -e "${defpm}.pm") {
      @pm = glob('*.pm');
      s/.pm$// for @pm;
      if (@pm == 1) { ($defpm = $pm[0]) =~ s/.pm$//; }
      elsif (@pm) {
        %xs = map { s/.xs$//; ($_,1) } glob('*.xs');  ## no critic
        if (keys %xs) {
            foreach my $pm (@pm) {
                $defpm = $pm, last if exists $xs{$pm};
            }
        }
      }
    }
    if (open(my $pm, '<', "${defpm}.pm")){
        while (<$pm>) {
            if (/^\s*package\s+([^;]+)/i) {
                $defname = $1;
                last;
            }
        }
        print "Warning (non-fatal): Couldn't find package name in ${defpm}.pm;\n\t",
                     "defaulting package name to $defname\n"
            if eof($pm);
        close $pm;
    }
    else {
        print "Warning (non-fatal): Couldn't find ${defpm}.pm;\n\t",
                     "defaulting package name to $defname\n";
    }
    $defname =~ s#[\d.\-_]+$##;
    $defname;
}

=item find_perl (override)

Use VMS file specification syntax and CLI commands to find and
invoke Perl images.

=cut

sub find_perl {
    my($self, $ver, $names, $dirs, $trace) = @_;
    my($vmsfile,@sdirs,@snames,@cand);
    my($rslt);
    my($inabs) = 0;
    local *TCF;

    if( $self->{PERL_CORE} ) {
        # Check in relative directories first, so we pick up the current
        # version of Perl if we're running MakeMaker as part of the main build.
        @sdirs = sort { my($absa) = $self->file_name_is_absolute($a);
                        my($absb) = $self->file_name_is_absolute($b);
                        if ($absa && $absb) { return $a cmp $b }
                        else { return $absa ? 1 : ($absb ? -1 : ($a cmp $b)); }
                      } @$dirs;
        # Check miniperl before perl, and check names likely to contain
        # version numbers before "generic" names, so we pick up an
        # executable that's less likely to be from an old installation.
        @snames = sort { my($ba) = $a =~ m!([^:>\]/]+)$!;  # basename
                         my($bb) = $b =~ m!([^:>\]/]+)$!;
                         my($ahasdir) = (length($a) - length($ba) > 0);
                         my($bhasdir) = (length($b) - length($bb) > 0);
                         if    ($ahasdir and not $bhasdir) { return 1; }
                         elsif ($bhasdir and not $ahasdir) { return -1; }
                         else { $bb =~ /\d/ <=> $ba =~ /\d/
                                  or substr($ba,0,1) cmp substr($bb,0,1)
                                  or length($bb) <=> length($ba) } } @$names;
    }
    else {
        @sdirs  = @$dirs;
        @snames = @$names;
    }

    # Image names containing Perl version use '_' instead of '.' under VMS
    s/\.(\d+)$/_$1/ for @snames;
    if ($trace >= 2){
        print "Looking for perl $ver by these names:\n";
        print "\t@snames,\n";
        print "in these dirs:\n";
        print "\t@sdirs\n";
    }
    foreach my $dir (@sdirs){
        next unless defined $dir; # $self->{PERL_SRC} may be undefined
        $inabs++ if $self->file_name_is_absolute($dir);
        if ($inabs == 1) {
            # We've covered relative dirs; everything else is an absolute
            # dir (probably an installed location).  First, we'll try
            # potential command names, to see whether we can avoid a long
            # MCR expression.
            foreach my $name (@snames) {
                push(@cand,$name) if $name =~ /^[\w\-\$]+$/;
            }
            $inabs++; # Should happen above in next $dir, but just in case...
        }
        foreach my $name (@snames){
            push @cand, ($name !~ m![/:>\]]!) ? $self->catfile($dir,$name)
                                              : $self->fixpath($name,0);
        }
    }
    foreach my $name (@cand) {
        print "Checking $name\n" if $trace >= 2;
        # If it looks like a potential command, try it without the MCR
        if ($name =~ /^[\w\-\$]+$/) {
            open(my $tcf, ">", "temp_mmvms.com")
                or die('unable to open temp file');
            print $tcf "\$ set message/nofacil/nosever/noident/notext\n";
            print $tcf "\$ $name -e \"require $ver; print \"\"VER_OK\\n\"\"\"\n";
            close $tcf;
            $rslt = `\@temp_mmvms.com` ;
            unlink('temp_mmvms.com');
            if ($rslt =~ /VER_OK/) {
                print "Using PERL=$name\n" if $trace;
                return $name;
            }
        }
        next unless $vmsfile = $self->maybe_command($name);
        $vmsfile =~ s/;[\d\-]*$//;  # Clip off version number; we can use a newer version as well
        print "Executing $vmsfile\n" if ($trace >= 2);
        open(my $tcf, '>', "temp_mmvms.com")
                or die('unable to open temp file');
        print $tcf "\$ set message/nofacil/nosever/noident/notext\n";
        print $tcf "\$ mcr $vmsfile -e \"require $ver; print \"\"VER_OK\\n\"\"\" \n";
        close $tcf;
        $rslt = `\@temp_mmvms.com`;
        unlink('temp_mmvms.com');
        if ($rslt =~ /VER_OK/) {
            print "Using PERL=MCR $vmsfile\n" if $trace;
            return "MCR $vmsfile";
        }
    }
    print "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n";
    0; # false and not empty
}

=item _fixin_replace_shebang (override)

Helper routine for L<< MM->fixin()|ExtUtils::MM_Unix/fixin >>, overridden
because there's no such thing as an
actual shebang line that will be interpreted by the shell, so we just prepend
$Config{startperl} and preserve the shebang line argument for any switches it
may contain.

=cut

sub _fixin_replace_shebang {
    my ( $self, $file, $line ) = @_;

    my ( undef, $arg ) = split ' ', $line, 2;

    return $Config{startperl} . "\n" . $Config{sharpbang} . "perl $arg\n";
}

=item maybe_command (override)

Follows VMS naming conventions for executable files.
If the name passed in doesn't exactly match an executable file,
appends F<.Exe> (or equivalent) to check for executable image, and F<.Com>
to check for DCL procedure.  If this fails, checks directories in DCL$PATH
and finally F<Sys$System:> for an executable file having the name specified,
with or without the F<.Exe>-equivalent suffix.

=cut

sub maybe_command {
    my($self,$file) = @_;
    return $file if -x $file && ! -d _;
    my(@dirs) = ('');
    my(@exts) = ('',$Config{'exe_ext'},'.exe','.com');

    if ($file !~ m![/:>\]]!) {
        for (my $i = 0; defined $ENV{"DCL\$PATH;$i"}; $i++) {
            my $dir = $ENV{"DCL\$PATH;$i"};
            $dir .= ':' unless $dir =~ m%[\]:]$%;
            push(@dirs,$dir);
        }
        push(@dirs,'Sys$System:');
        foreach my $dir (@dirs) {
            my $sysfile = "$dir$file";
            foreach my $ext (@exts) {
                return $file if -x "$sysfile$ext" && ! -d _;
            }
        }
    }
    return 0;
}


=item pasthru (override)

The list of macro definitions to be passed through must be specified using
the /MACRO qualifier and must not add another /DEFINE qualifier.  We prepend
our own comma here to the contents of $(PASTHRU_DEFINE) because it is often
empty and a comma always present in CCFLAGS would generate a missing
qualifier value error.

=cut

sub pasthru {
    my($self) = shift;
    my $pasthru = $self->SUPER::pasthru;
    $pasthru =~ s|(PASTHRU\s*=\s*)|$1/MACRO=(|;
    $pasthru =~ s|\n\z|)\n|m;
    $pasthru =~ s|/defi?n?e?=\(?([^\),]+)\)?|,$1|ig;

    return $pasthru;
}


=item pm_to_blib (override)

VMS wants a dot in every file so we can't have one called 'pm_to_blib',
it becomes 'pm_to_blib.' and MMS/K isn't smart enough to know that when
you have a target called 'pm_to_blib' it should look for 'pm_to_blib.'.

So in VMS its pm_to_blib.ts.

=cut

sub pm_to_blib {
    my $self = shift;

    my $make = $self->SUPER::pm_to_blib;

    $make =~ s{^pm_to_blib :}{pm_to_blib.ts :}m;
    $make =~ s{\$\(TOUCH\) pm_to_blib}{\$(TOUCH) pm_to_blib.ts};

    $make = <<'MAKE' . $make;
# Dummy target to match Unix target name; we use pm_to_blib.ts as
# timestamp file to avoid repeated invocations under VMS
pm_to_blib : pm_to_blib.ts
	$(NOECHO) $(NOOP)

MAKE

    return $make;
}


=item perl_script (override)

If name passed in doesn't specify a readable file, appends F<.com> or
F<.pl> and tries again, since it's customary to have file types on all files
under VMS.

=cut

sub perl_script {
    my($self,$file) = @_;
    return $file if -r $file && ! -d _;
    return "$file.com" if -r "$file.com";
    return "$file.pl" if -r "$file.pl";
    return '';
}


=item replace_manpage_separator

Use as separator a character which is legal in a VMS-syntax file name.

=cut

sub replace_manpage_separator {
    my($self,$man) = @_;
    $man = unixify($man);
    $man =~ s#/+#__#g;
    $man;
}

=item init_DEST

(override) Because of the difficulty concatenating VMS filepaths we
must pre-expand the DEST* variables.

=cut

sub init_DEST {
    my $self = shift;

    $self->SUPER::init_DEST;

    # Expand DEST variables.
    foreach my $var ($self->installvars) {
        my $destvar = 'DESTINSTALL'.$var;
        $self->{$destvar} = $self->eliminate_macros($self->{$destvar});
    }
}


=item init_DIRFILESEP

No separator between a directory path and a filename on VMS.

=cut

sub init_DIRFILESEP {
    my($self) = shift;

    $self->{DIRFILESEP} = '';
    return 1;
}


=item init_main (override)


=cut

sub init_main {
    my($self) = shift;

    $self->SUPER::init_main;

    $self->{DEFINE} ||= '';
    if ($self->{DEFINE} ne '') {
        my(@terms) = split(/\s+/,$self->{DEFINE});
        my(@defs,@udefs);
        foreach my $def (@terms) {
            next unless $def;
            my $targ = \@defs;
            if ($def =~ s/^-([DU])//) {    # If it was a Unix-style definition
                $targ = \@udefs if $1 eq 'U';
                $def =~ s/='(.*)'$/=$1/;  # then remove shell-protection ''
                $def =~ s/^'(.*)'$/$1/;   # from entire term or argument
            }
            if ($def =~ /=/) {
                $def =~ s/"/""/g;  # Protect existing " from DCL
                $def = qq["$def"]; # and quote to prevent parsing of =
            }
            push @$targ, $def;
        }

        $self->{DEFINE} = '';
        if (@defs)  {
            $self->{DEFINE}  = '/Define=(' . join(',',@defs)  . ')';
        }
        if (@udefs) {
            $self->{DEFINE} .= '/Undef=('  . join(',',@udefs) . ')';
        }
    }
}

=item init_tools (override)

Provide VMS-specific forms of various utility commands.

Sets DEV_NULL to nothing because I don't know how to do it on VMS.

Changes EQUALIZE_TIMESTAMP to set revision date of target file to
one second later than source file, since MMK interprets precisely
equal revision dates for a source and target file as a sign that the
target needs to be updated.

=cut

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

    $self->{NOOP}               = 'Continue';
    $self->{NOECHO}             ||= '@ ';

    $self->{MAKEFILE}           ||= $self->{FIRST_MAKEFILE} || 'Descrip.MMS';
    $self->{FIRST_MAKEFILE}     ||= $self->{MAKEFILE};
    $self->{MAKE_APERL_FILE}    ||= 'Makeaperl.MMS';
    $self->{MAKEFILE_OLD}       ||= $self->eliminate_macros('$(FIRST_MAKEFILE)_old');
#
#   If an extension is not specified, then MMS/MMK assumes an
#   an extension of .MMS.  If there really is no extension,
#   then a trailing "." needs to be appended to specify a
#   a null extension.
#
    $self->{MAKEFILE} .= '.' unless $self->{MAKEFILE} =~ m/\./;
    $self->{FIRST_MAKEFILE} .= '.' unless $self->{FIRST_MAKEFILE} =~ m/\./;
    $self->{MAKE_APERL_FILE} .= '.' unless $self->{MAKE_APERL_FILE} =~ m/\./;
    $self->{MAKEFILE_OLD} .= '.' unless $self->{MAKEFILE_OLD} =~ m/\./;

    $self->{MACROSTART}         ||= '/Macro=(';
    $self->{MACROEND}           ||= ')';
    $self->{USEMAKEFILE}        ||= '/Descrip=';

    $self->{EQUALIZE_TIMESTAMP} ||= '$(ABSPERLRUN) -we "open F,qq{>>$ARGV[1]};close F;utime(0,(stat($ARGV[0]))[9]+1,$ARGV[1])"';

    $self->{MOD_INSTALL} ||=
      $self->oneliner(<<'CODE', ['-MExtUtils::Install']);
install([ from_to => {split('\|', <STDIN>)}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]);
CODE

    $self->{UMASK_NULL} = '! ';

    $self->SUPER::init_tools;

    # Use the default shell
    $self->{SHELL}    ||= 'Posix';

    # Redirection on VMS goes before the command, not after as on Unix.
    # $(DEV_NULL) is used once and its not worth going nuts over making
    # it work.  However, Unix's DEV_NULL is quite wrong for VMS.
    $self->{DEV_NULL}   = '';

    return;
}

=item init_platform (override)

Add PERL_VMS, MM_VMS_REVISION and MM_VMS_VERSION.

MM_VMS_REVISION is for backwards compatibility before MM_VMS had a
$VERSION.

=cut

sub init_platform {
    my($self) = shift;

    $self->{MM_VMS_REVISION} = $Revision;
    $self->{MM_VMS_VERSION}  = $VERSION;
    $self->{PERL_VMS} = $self->catdir($self->{PERL_SRC}, 'VMS')
      if $self->{PERL_SRC};
}


=item platform_constants

=cut

sub platform_constants {
    my($self) = shift;
    my $make_frag = '';

    foreach my $macro (qw(PERL_VMS MM_VMS_REVISION MM_VMS_VERSION))
    {
        next unless defined $self->{$macro};
        $make_frag .= "$macro = $self->{$macro}\n";
    }

    return $make_frag;
}


=item init_VERSION (override)

Override the *DEFINE_VERSION macros with VMS semantics.  Translate the
MAKEMAKER filepath to VMS style.

=cut

sub init_VERSION {
    my $self = shift;

    $self->SUPER::init_VERSION;

    $self->{DEFINE_VERSION}    = '"$(VERSION_MACRO)=""$(VERSION)"""';
    $self->{XS_DEFINE_VERSION} = '"$(XS_VERSION_MACRO)=""$(XS_VERSION)"""';
    $self->{MAKEMAKER} = vmsify($INC{'ExtUtils/MakeMaker.pm'});
}


=item constants (override)

Fixes up numerous file and directory macros to insure VMS syntax
regardless of input syntax.  Also makes lists of files
comma-separated.

=cut

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

    # Be kind about case for pollution
    for (@ARGV) { $_ = uc($_) if /POLLUTE/i; }

    # Cleanup paths for directories in MMS macros.
    foreach my $macro ( qw [
            INST_BIN INST_SCRIPT INST_LIB INST_ARCHLIB
            PERL_LIB PERL_ARCHLIB PERL_ARCHLIBDEP
            PERL_INC PERL_SRC ],
                        (map { 'INSTALL'.$_ } $self->installvars),
                        (map { 'DESTINSTALL'.$_ } $self->installvars)
                      )
    {
        next unless defined $self->{$macro};
        next if $macro =~ /MAN/ && $self->{$macro} eq 'none';
        $self->{$macro} = $self->fixpath($self->{$macro},1);
    }

    # Cleanup paths for files in MMS macros.
    foreach my $macro ( qw[LIBPERL_A FIRST_MAKEFILE MAKEFILE_OLD
                           MAKE_APERL_FILE MYEXTLIB] )
    {
        next unless defined $self->{$macro};
        $self->{$macro} = $self->fixpath($self->{$macro},0);
    }

    # Fixup files for MMS macros
    # XXX is this list complete?
    for my $macro (qw/
                   FULLEXT VERSION_FROM
	      /	) {
        next unless defined $self->{$macro};
        $self->{$macro} = $self->fixpath($self->{$macro},0);
    }


    for my $macro (qw/
                   OBJECT LDFROM
	      /	) {
        next unless defined $self->{$macro};

        # Must expand macros before splitting on unescaped whitespace.
        $self->{$macro} = $self->eliminate_macros($self->{$macro});
        if ($self->{$macro} =~ /(?<!\^)\s/) {
            $self->{$macro} =~ s/(\\)?\n+\s+/ /g;
            $self->{$macro} = $self->wraplist(
                map $self->fixpath($_,0), split /,?(?<!\^)\s+/, $self->{$macro}
            );
        }
        else {
            $self->{$macro} = $self->fixpath($self->{$macro},0);
        }
    }

    for my $macro (qw/ XS MAN1PODS MAN3PODS PM /) {
        # Where is the space coming from? --jhi
        next unless $self ne " " && defined $self->{$macro};
        my %tmp = ();
        for my $key (keys %{$self->{$macro}}) {
            $tmp{$self->fixpath($key,0)} =
                                     $self->fixpath($self->{$macro}{$key},0);
        }
        $self->{$macro} = \%tmp;
    }

    for my $macro (qw/ C O_FILES H /) {
        next unless defined $self->{$macro};
        my @tmp = ();
        for my $val (@{$self->{$macro}}) {
            push(@tmp,$self->fixpath($val,0));
        }
        $self->{$macro} = \@tmp;
    }

    # mms/k does not define a $(MAKE) macro.
    $self->{MAKE} = '$(MMS)$(MMSQUALIFIERS)';

    return $self->SUPER::constants;
}


=item special_targets

Clear the default .SUFFIXES and put in our own list.

=cut

sub special_targets {
    my $self = shift;

    my $make_frag .= <<'MAKE_FRAG';
.SUFFIXES :
.SUFFIXES : $(OBJ_EXT) .c .cpp .cxx .xs

MAKE_FRAG

    return $make_frag;
}

=item cflags (override)

Bypass shell script and produce qualifiers for CC directly (but warn
user if a shell script for this extension exists).  Fold multiple
/Defines into one, since some C compilers pay attention to only one
instance of this qualifier on the command line.

=cut

sub cflags {
    my($self,$libperl) = @_;
    my($quals) = $self->{CCFLAGS} || $Config{'ccflags'};
    my($definestr,$undefstr,$flagoptstr) = ('','','');
    my($incstr) = '/Include=($(PERL_INC)';
    my($name,$sys,@m);

    ( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ;
    print "Unix shell script ".$Config{"$self->{'BASEEXT'}_cflags"}.
         " required to modify CC command for $self->{'BASEEXT'}\n"
    if ($Config{$name});

    if ($quals =~ / -[DIUOg]/) {
	while ($quals =~ / -([Og])(\d*)\b/) {
	    my($type,$lvl) = ($1,$2);
	    $quals =~ s/ -$type$lvl\b\s*//;
	    if ($type eq 'g') { $flagoptstr = '/NoOptimize'; }
	    else { $flagoptstr = '/Optimize' . (defined($lvl) ? "=$lvl" : ''); }
	}
	while ($quals =~ / -([DIU])(\S+)/) {
	    my($type,$def) = ($1,$2);
	    $quals =~ s/ -$type$def\s*//;
	    $def =~ s/"/""/g;
	    if    ($type eq 'D') { $definestr .= qq["$def",]; }
	    elsif ($type eq 'I') { $incstr .= ',' . $self->fixpath($def,1); }
	    else                 { $undefstr  .= qq["$def",]; }
	}
    }
    if (length $quals and $quals !~ m!/!) {
	warn "MM_VMS: Ignoring unrecognized CCFLAGS elements \"$quals\"\n";
	$quals = '';
    }
    $definestr .= q["PERL_POLLUTE",] if $self->{POLLUTE};
    if (length $definestr) { chop($definestr); $quals .= "/Define=($definestr)"; }
    if (length $undefstr)  { chop($undefstr);  $quals .= "/Undef=($undefstr)";   }
    # Deal with $self->{DEFINE} here since some C compilers pay attention
    # to only one /Define clause on command line, so we have to
    # conflate the ones from $Config{'ccflags'} and $self->{DEFINE}
    # ($self->{DEFINE} has already been VMSified in constants() above)
    if ($self->{DEFINE}) { $quals .= $self->{DEFINE}; }
    for my $type (qw(Def Undef)) {
	my(@terms);
	while ($quals =~ m:/${type}i?n?e?=([^/]+):ig) {
		my $term = $1;
		$term =~ s:^\((.+)\)$:$1:;
		push @terms, $term;
	}
	if ($type eq 'Def') {
	    push @terms, qw[ $(DEFINE_VERSION) $(XS_DEFINE_VERSION) ];
	}
	if (@terms) {
	    $quals =~ s:/${type}i?n?e?=[^/]+::ig;
            # PASTHRU_DEFINE will have its own comma
	    $quals .= "/${type}ine=(" . join(',',@terms) . ($type eq 'Def' ? '$(PASTHRU_DEFINE)' : '') . ')';
	}
    }

    $libperl or $libperl = $self->{LIBPERL_A} || "libperl.olb";

    # Likewise with $self->{INC} and /Include
    if ($self->{'INC'}) {
	my(@includes) = split(/\s+/,$self->{INC});
	foreach (@includes) {
	    s/^-I//;
	    $incstr .= ','.$self->fixpath($_,1);
	}
    }
    $quals .= "$incstr)";
#    $quals =~ s/,,/,/g; $quals =~ s/\(,/(/g;
    $self->{CCFLAGS} = $quals;

    $self->{PERLTYPE} ||= '';

    $self->{OPTIMIZE} ||= $flagoptstr || $Config{'optimize'};
    if ($self->{OPTIMIZE} !~ m!/!) {
	if    ($self->{OPTIMIZE} =~ m!-g!) { $self->{OPTIMIZE} = '/Debug/NoOptimize' }
	elsif ($self->{OPTIMIZE} =~ /-O(\d*)/) {
	    $self->{OPTIMIZE} = '/Optimize' . (defined($1) ? "=$1" : '');
	}
	else {
	    warn "MM_VMS: Can't parse OPTIMIZE \"$self->{OPTIMIZE}\"; using default\n" if length $self->{OPTIMIZE};
	    $self->{OPTIMIZE} = '/Optimize';
	}
    }

    return $self->{CFLAGS} = qq{
CCFLAGS = $self->{CCFLAGS}
OPTIMIZE = $self->{OPTIMIZE}
PERLTYPE = $self->{PERLTYPE}
};
}

=item const_cccmd (override)

Adds directives to point C preprocessor to the right place when
handling #include E<lt>sys/foo.hE<gt> directives.  Also constructs CC
command line a bit differently than MM_Unix method.

=cut

sub const_cccmd {
    my($self,$libperl) = @_;
    my(@m);

    return $self->{CONST_CCCMD} if $self->{CONST_CCCMD};
    return '' unless $self->needs_linking();
    if ($Config{'vms_cc_type'} eq 'gcc') {
        push @m,'
.FIRST
	',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" Then Define/NoLog SYS GNU_CC_Include:[VMS]';
    }
    elsif ($Config{'vms_cc_type'} eq 'vaxc') {
        push @m,'
.FIRST
	',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").eqs."" Then Define/NoLog SYS Sys$Library
	',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").nes."" Then Define/NoLog SYS VAXC$Include';
    }
    else {
        push @m,'
.FIRST
	',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").eqs."" Then Define/NoLog SYS ',
		($Config{'archname'} eq 'VMS_AXP' ? 'Sys$Library' : 'DECC$Library_Include'),'
	',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").nes."" Then Define/NoLog SYS DECC$System_Include';
    }

    push(@m, "\n\nCCCMD = $Config{'cc'} \$(CCFLAGS)\$(OPTIMIZE)\n");

    $self->{CONST_CCCMD} = join('',@m);
}


=item tools_other (override)

Throw in some dubious extra macros for Makefile args.

Also keep around the old $(SAY) macro in case somebody's using it.

=cut

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

    # XXX Are these necessary?  Does anyone override them?  They're longer
    # than just typing the literal string.
    my $extra_tools = <<'EXTRA_TOOLS';

# Just in case anyone is using the old macro.
USEMACROS = $(MACROSTART)
SAY = $(ECHO)

EXTRA_TOOLS

    return $self->SUPER::tools_other . $extra_tools;
}

=item init_dist (override)

VMSish defaults for some values.

  macro         description                     default

  ZIPFLAGS      flags to pass to ZIP            -Vu

  COMPRESS      compression command to          gzip
                use for tarfiles
  SUFFIX        suffix to put on                -gz
                compressed files

  SHAR          shar command to use             vms_share

  DIST_DEFAULT  default target to use to        tardist
                create a distribution

  DISTVNAME     Use VERSION_SYM instead of      $(DISTNAME)-$(VERSION_SYM)
                VERSION for the name

=cut

sub init_dist {
    my($self) = @_;
    $self->{ZIPFLAGS}     ||= '-Vu';
    $self->{COMPRESS}     ||= 'gzip';
    $self->{SUFFIX}       ||= '-gz';
    $self->{SHAR}         ||= 'vms_share';
    $self->{DIST_DEFAULT} ||= 'zipdist';

    $self->SUPER::init_dist;

    $self->{DISTVNAME} = "$self->{DISTNAME}-$self->{VERSION_SYM}"
      unless $self->{ARGS}{DISTVNAME};

    return;
}

=item c_o (override)

Use VMS syntax on command line.  In particular, $(DEFINE) and
$(PERL_INC) have been pulled into $(CCCMD).  Also use MM[SK] macros.

=cut

sub c_o {
    my($self) = @_;
    return '' unless $self->needs_linking();
    '
.c$(OBJ_EXT) :
	$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)

.cpp$(OBJ_EXT) :
	$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)

.cxx$(OBJ_EXT) :
	$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)

';
}

=item xs_c (override)

Use MM[SK] macros.

=cut

sub xs_c {
    my($self) = @_;
    return '' unless $self->needs_linking();
    '
.xs.c :
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
	$(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
';
}

=item xs_o (override)

Use MM[SK] macros, and VMS command line for C compiler.

=cut

sub xs_o {
    my ($self) = @_;
    return '' unless $self->needs_linking();
    my $frag = '
.xs$(OBJ_EXT) :
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
	$(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
	$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
';
    if ($self->{XSMULTI}) {
	for my $ext ($self->_xs_list_basenames) {
	    my $version = $self->parse_version("$ext.pm");
	    my $ccflags = $self->{CCFLAGS};
	    $ccflags =~ s/\$\(DEFINE_VERSION\)/\"VERSION_MACRO=\\"\"$version\\"\"/;
	    $ccflags =~ s/\$\(XS_DEFINE_VERSION\)/\"XS_VERSION_MACRO=\\"\"$version\\"\"/;
	    $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'INC');
	    $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'DEFINE');

	    $frag .= _sprintf562 <<'EOF', $ext, $ccflags;

%1$s$(OBJ_EXT) : %1$s.xs
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs > $(MMS$TARGET_NAME).xsc
	$(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
	$(CC)%2$s$(OPTIMIZE) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
EOF
	}
    }
    $frag;
}

=item _xsbuild_replace_macro (override)

There is no simple replacement possible since a qualifier and all its
subqualifiers must be considered together, so we use our own utility
routine for the replacement.

=cut

sub _xsbuild_replace_macro {
    my ($self, undef, $xstype, $ext, $varname) = @_;
    my $value = $self->_xsbuild_value($xstype, $ext, $varname);
    return unless defined $value;
    $_[1] = _vms_replace_qualifier($self, $_[1], $value, $varname);
}

=item _xsbuild_value (override)

Convert the extension spec to Unix format, as that's what will
match what's in the XSBUILD data structure.

=cut

sub _xsbuild_value {
    my ($self, $xstype, $ext, $varname) = @_;
    $ext = unixify($ext);
    return $self->SUPER::_xsbuild_value($xstype, $ext, $varname);
}

sub _vms_replace_qualifier {
    my ($self, $flags, $newflag, $macro) = @_;
    my $qual_type;
    my $type_suffix;
    my $quote_subquals = 0;
    my @subquals_new = split /\s+/, $newflag;

    if ($macro eq 'DEFINE') {
        $qual_type = 'Def';
        $type_suffix = 'ine';
        map { $_ =~ s/^-D// } @subquals_new;
        $quote_subquals = 1;
    }
    elsif ($macro eq 'INC') {
        $qual_type = 'Inc';
        $type_suffix = 'lude';
        map { $_ =~ s/^-I//; $_ = $self->fixpath($_) } @subquals_new;
    }

    my @subquals = ();
    while ($flags =~ m:/${qual_type}\S{0,4}=([^/]+):ig) {
        my $term = $1;
        $term =~ s/\"//g;
        $term =~ s:^\((.+)\)$:$1:;
        push @subquals, split /,/, $term;
    }
    for my $new (@subquals_new) {
        my ($sq_new, $sqval_new) = split /=/, $new;
        my $replaced_old = 0;
        for my $old (@subquals) {
            my ($sq, $sqval) = split /=/, $old;
            if ($sq_new eq $sq) {
                $old = $sq_new;
                $old .= '=' . $sqval_new if defined($sqval_new) and length($sqval_new);
                $replaced_old = 1;
                last;
            }
        }
        push @subquals, $new unless $replaced_old;
    }

    if (@subquals) {
        $flags =~ s:/${qual_type}\S{0,4}=[^/]+::ig;
        # add quotes if requested but not for unexpanded macros
        map { $_ = qq/"$_"/ if $_ !~ m/^\$\(/ } @subquals if $quote_subquals;
        $flags .= "/${qual_type}$type_suffix=(" . join(',',@subquals) . ')';
    }

    return $flags;
}


sub xs_dlsyms_ext {
    '.opt';
}

=item dlsyms (override)

Create VMS linker options files specifying universal symbols for this
extension's shareable image(s), and listing other shareable images or
libraries to which it should be linked.

=cut

sub dlsyms {
    my ($self, %attribs) = @_;
    return '' unless $self->needs_linking;
    $self->xs_dlsyms_iterator;
}

sub xs_make_dlsyms {
    my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
    my @m;
    my $instloc;
    if ($self->{XSMULTI}) {
	my ($v, $d, $f) = File::Spec->splitpath($target);
	my @d = File::Spec->splitdir($d);
	shift @d if $d[0] eq 'lib';
	$instloc = $self->catfile('$(INST_ARCHLIB)', 'auto', @d, $f);
	push @m,"\ndynamic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
	  unless $self->{SKIPHASH}{'dynamic'};
	push @m,"\nstatic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
	  unless $self->{SKIPHASH}{'static'};
	push @m, "\n", sprintf <<'EOF', $instloc, $target;
%s : %s
	$(CP) $(MMS$SOURCE) $(MMS$TARGET)
EOF
    }
    else {
	push @m,"\ndynamic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
	  unless $self->{SKIPHASH}{'dynamic'};
	push @m,"\nstatic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
	  unless $self->{SKIPHASH}{'static'};
	push @m, "\n", sprintf <<'EOF', $target;
$(INST_ARCHAUTODIR)$(BASEEXT).opt : %s
	$(CP) $(MMS$SOURCE) $(MMS$TARGET)
EOF
    }
    push @m,
     "\n$target : $dep\n\t",
     q!$(PERLRUN) -MExtUtils::Mksymlists -e "Mksymlists('NAME'=>'!, $name,
     q!', 'DLBASE' => '!,$dlbase,
     q!', 'DL_FUNCS' => !,neatvalue($funcs),
     q!, 'FUNCLIST' => !,neatvalue($funclist),
     q!, 'IMPORTS' => !,neatvalue($imports),
     q!, 'DL_VARS' => !, neatvalue($vars);
    push @m, $extra if defined $extra;
    push @m, qq!);"\n\t!;
    # Can't use dlbase as it's been through mod2fname.
    my $olb_base = basename($target, '.opt');
    if ($self->{XSMULTI}) {
        # We've been passed everything but the kitchen sink -- and the location of the
        # static library we're using to build the dynamic library -- so concoct that
        # location from what we do have.
        my $olb_dir = $self->catdir(dirname($instloc), $olb_base);
        push @m, qq!\$(PERL) -e "print ""${olb_dir}${olb_base}\$(LIB_EXT)/Include=!;
        push @m, ($Config{d_vms_case_sensitive_symbols} ? uc($olb_base) : $olb_base);
        push @m, '\n' . $olb_dir . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
    }
    else {
        push @m, qq!\$(PERL) -e "print ""\$(INST_ARCHAUTODIR)${olb_base}\$(LIB_EXT)/Include=!;
        if ($self->{OBJECT} =~ /\bBASEEXT\b/ or
            $self->{OBJECT} =~ /\b$self->{BASEEXT}\b/i) {
            push @m, ($Config{d_vms_case_sensitive_symbols}
	              ? uc($self->{BASEEXT}) :'$(BASEEXT)');
        }
        else {  # We don't have a "main" object file, so pull 'em all in
            # Upcase module names if linker is being case-sensitive
            my($upcase) = $Config{d_vms_case_sensitive_symbols};
            my(@omods) = split ' ', $self->eliminate_macros($self->{OBJECT});
            for (@omods) {
                s/\.[^.]*$//;         # Trim off file type
                s[\$\(\w+_EXT\)][];   # even as a macro
                s/.*[:>\/\]]//;       # Trim off dir spec
                $_ = uc if $upcase;
            };
            my(@lines);
            my $tmp = shift @omods;
            foreach my $elt (@omods) {
                $tmp .= ",$elt";
                if (length($tmp) > 80) { push @lines, $tmp;  $tmp = ''; }
            }
            push @lines, $tmp;
            push @m, '(', join( qq[, -\\n\\t"";" >>\$(MMS\$TARGET)\n\t\$(PERL) -e "print ""], @lines),')';
        }
        push @m, '\n$(INST_ARCHAUTODIR)' . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
    }
    if (length $self->{LDLOADLIBS}) {
        my($line) = '';
        foreach my $lib (split ' ', $self->{LDLOADLIBS}) {
            $lib =~ s%\$%\\\$%g;  # Escape '$' in VMS filespecs
            if (length($line) + length($lib) > 160) {
                push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n";
                $line = $lib . '\n';
            }
            else { $line .= $lib . '\n'; }
        }
        push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n" if $line;
    }
    join '', @m;
}


=item xs_obj_opt

Override to fixup -o flags.

=cut

sub xs_obj_opt {
    my ($self, $output_file) = @_;
    "/OBJECT=$output_file";
}

=item dynamic_lib (override)

Use VMS Link command.

=cut

sub xs_dynamic_lib_macros {
    my ($self, $attribs) = @_;
    my $otherldflags = $attribs->{OTHERLDFLAGS} || "";
    my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
    sprintf <<'EOF', $otherldflags, $inst_dynamic_dep;
# This section creates the dynamically loadable objects from relevant
# objects and possibly $(MYEXTLIB).
OTHERLDFLAGS = %s
INST_DYNAMIC_DEP = %s
EOF
}

sub xs_make_dynamic_lib {
    my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
    my $shr = $Config{'dbgprefix'} . 'PerlShr';
    $exportlist =~ s/.def$/.opt/;  # it's a linker options file
    #                    1    2       3            4     5
    _sprintf562 <<'EOF', $to, $todir, $exportlist, $shr, "$shr Sys\$Share:$shr.$Config{'dlext'}";
%1$s : $(INST_STATIC) $(PERL_INC)perlshr_attr.opt %2$s$(DFSEP).exists %3$s $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
	If F$TrnLNm("%4$s").eqs."" Then Define/NoLog/User %5$s
	Link $(LDFLAGS) /Shareable=$(MMS$TARGET)$(OTHERLDFLAGS) %3$s/Option,$(PERL_INC)perlshr_attr.opt/Option
EOF
}

=item xs_make_static_lib (override)

Use VMS commands to manipulate object library.

=cut

sub xs_make_static_lib {
    my ($self, $object, $to, $todir) = @_;

    my @objects;
    if ($self->{XSMULTI}) {
        # The extension name should be the main object file name minus file type.
        my $lib = $object;
        $lib =~ s/\$\(OBJ_EXT\)\z//;
        my $override = $self->_xsbuild_value('xs', $lib, 'OBJECT');
        $object = $override if defined $override;
        @objects = map { $self->fixpath($_,0) } split /(?<!\^)\s+/, $object;
    }
    else {
        push @objects, $object;
    }

    my @m;
    for my $obj (@objects) {
        push(@m, sprintf "\n%s : %s\$(DFSEP).exists", $obj, $todir);
    }
    push(@m, sprintf "\n\n%s : %s \$(MYEXTLIB)\n", $to, (join ' ', @objects));

    # If this extension has its own library (eg SDBM_File)
    # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
    push(@m, "\t",'$(CP) $(MYEXTLIB) $(MMS$TARGET)',"\n") if $self->{MYEXTLIB};

    push(@m,"\t",'If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)',"\n");

    # if there was a library to copy, then we can't use MMS$SOURCE_LIST,
    # 'cause it's a library and you can't stick them in other libraries.
    # In that case, we use $OBJECT instead and hope for the best
    if ($self->{MYEXTLIB}) {
        for my $obj (@objects) {
            push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) ' . $obj,"\n");
        }
    }
    else {
      push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(MMS$SOURCE_LIST)',"\n");
    }

    push @m, "\t\$(NOECHO) \$(PERL) -e 1 >\$(INST_ARCHAUTODIR)extralibs.ld\n";
    foreach my $lib (split ' ', $self->{EXTRALIBS}) {
      push(@m,"\t",'$(NOECHO) $(PERL) -e "print qq{',$lib,'\n}" >>$(INST_ARCHAUTODIR)extralibs.ld',"\n");
    }
    join('',@m);
}


=item static_lib_pure_cmd (override)

Use VMS commands to manipulate object library.

=cut

sub static_lib_pure_cmd {
    my ($self, $from) = @_;

    sprintf <<'MAKE_FRAG', $from;
	If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)
	Library/Object/Replace $(MMS$TARGET) %s
MAKE_FRAG
}

=item xs_static_lib_is_xs

=cut

sub xs_static_lib_is_xs {
    return 1;
}

=item extra_clean_files

Clean up some OS specific files.  Plus the temp file used to shorten
a lot of commands.  And the name mangler database.

=cut

sub extra_clean_files {
    return qw(
              *.Map *.Dmp *.Lis *.cpp *.$(DLEXT) *.Opt $(BASEEXT).bso
              .MM_Tmp cxx_repository
             );
}


=item zipfile_target

=item tarfile_target

=item shdist_target

Syntax for invoking shar, tar and zip differs from that for Unix.

=cut

sub zipfile_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
$(DISTVNAME).zip : distdir
	$(PREOP)
	$(ZIP) "$(ZIPFLAGS)" $(MMS$TARGET) [.$(DISTVNAME)...]*.*;
	$(RM_RF) $(DISTVNAME)
	$(POSTOP)
MAKE_FRAG
}

sub tarfile_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
$(DISTVNAME).tar$(SUFFIX) : distdir
	$(PREOP)
	$(TO_UNIX)
	$(TAR) "$(TARFLAGS)" $(DISTVNAME).tar [.$(DISTVNAME)...]
	$(RM_RF) $(DISTVNAME)
	$(COMPRESS) $(DISTVNAME).tar
	$(POSTOP)
MAKE_FRAG
}

sub shdist_target {
    my($self) = shift;

    return <<'MAKE_FRAG';
shdist : distdir
	$(PREOP)
	$(SHAR) [.$(DISTVNAME)...]*.*; $(DISTVNAME).share
	$(RM_RF) $(DISTVNAME)
	$(POSTOP)
MAKE_FRAG
}


# --- Test and Installation Sections ---

=item install (override)

Work around DCL's 255 character limit several times,and use
VMS-style command line quoting in a few cases.

=cut

sub install {
    my($self, %attribs) = @_;
    my(@m);

    push @m, q[
install :: all pure_install doc_install
	$(NOECHO) $(NOOP)

install_perl :: all pure_perl_install doc_perl_install
	$(NOECHO) $(NOOP)

install_site :: all pure_site_install doc_site_install
	$(NOECHO) $(NOOP)

install_vendor :: all pure_vendor_install doc_vendor_install
	$(NOECHO) $(NOOP)

pure_install :: pure_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

doc_install :: doc_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

pure__install : pure_site_install
	$(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site"

doc__install : doc_site_install
	$(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site"

# This hack brought to you by DCL's 255-character command line limit
pure_perl_install ::
];
    push @m,
q[	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
] unless $self->{NO_PACKLIST};

    push @m,
q[	$(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLPRIVLIB)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLARCHLIB)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLBIN)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) " >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLMAN3DIR)" >>.MM_tmp
	$(NOECHO) $(MOD_INSTALL) <.MM_tmp
	$(NOECHO) $(RM_F) .MM_tmp
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q["

# Likewise
pure_site_install ::
];
    push @m,
q[	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
] unless $self->{NO_PACKLIST};

    push @m,
q[	$(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLSITELIB)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLSITEARCH)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLSITEBIN)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLSITEMAN1DIR)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLSITEMAN3DIR)" >>.MM_tmp
	$(NOECHO) $(MOD_INSTALL) <.MM_tmp
	$(NOECHO) $(RM_F) .MM_tmp
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q["

pure_vendor_install ::
];
    push @m,
q[	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
	$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLVENDORARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
] unless $self->{NO_PACKLIST};

    push @m,
q[	$(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLVENDORLIB)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLVENDORARCH)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLVENDORBIN)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLVENDORMAN1DIR)|" >>.MM_tmp
	$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLVENDORMAN3DIR)" >>.MM_tmp
	$(NOECHO) $(MOD_INSTALL) <.MM_tmp
	$(NOECHO) $(RM_F) .MM_tmp

];

    push @m, q[
# Ditto
doc_perl_install ::
	$(NOECHO) $(NOOP)

# And again
doc_site_install ::
	$(NOECHO) $(NOOP)

doc_vendor_install ::
	$(NOECHO) $(NOOP)

] if $self->{NO_PERLLOCAL};

    push @m, q[
# Ditto
doc_perl_install ::
	$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
	$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
	$(NOECHO) $(ECHO_N) "installed into|$(INSTALLPRIVLIB)|" >.MM_tmp
	$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
	$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
	$(NOECHO) $(RM_F) .MM_tmp

# And again
doc_site_install ::
	$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
	$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
	$(NOECHO) $(ECHO_N) "installed into|$(INSTALLSITELIB)|" >.MM_tmp
	$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
	$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
	$(NOECHO) $(RM_F) .MM_tmp

doc_vendor_install ::
	$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
	$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
	$(NOECHO) $(ECHO_N) "installed into|$(INSTALLVENDORLIB)|" >.MM_tmp
	$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
	$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
	$(NOECHO) $(RM_F) .MM_tmp

] unless $self->{NO_PERLLOCAL};

    push @m, q[
uninstall :: uninstall_from_$(INSTALLDIRS)dirs
	$(NOECHO) $(NOOP)

uninstall_from_perldirs ::
	$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[

uninstall_from_sitedirs ::
	$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[

uninstall_from_vendordirs ::
	$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{VENDORARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[
];

    join('',@m);
}

=item perldepend (override)

Use VMS-style syntax for files; it's cheaper to just do it directly here
than to have the L<MM_Unix|ExtUtils::MM_Unix> method call C<catfile>
repeatedly.  Also, if we have to rebuild Config.pm, use MM[SK] to do it.

=cut

sub perldepend {
    my($self) = @_;
    my(@m);

    if ($self->{OBJECT}) {
        # Need to add an object file dependency on the perl headers.
        # this is very important for XS modules in perl.git development.

        push @m, $self->_perl_header_files_fragment(""); # empty separator on VMS as its in the $(PERL_INC)
    }

    if ($self->{PERL_SRC}) {
	my(@macros);
	my($mmsquals) = '$(USEMAKEFILE)[.vms]$(FIRST_MAKEFILE)';
	push(@macros,'__AXP__=1') if $Config{'archname'} eq 'VMS_AXP';
	push(@macros,'DECC=1')    if $Config{'vms_cc_type'} eq 'decc';
	push(@macros,'GNUC=1')    if $Config{'vms_cc_type'} eq 'gcc';
	push(@macros,'SOCKET=1')  if $Config{'d_has_sockets'};
	push(@macros,qq["CC=$Config{'cc'}"])  if $Config{'cc'} =~ m!/!;
	$mmsquals .= '$(USEMACROS)' . join(',',@macros) . '$(MACROEND)' if @macros;
	push(@m,q[
# Check for unpropagated config.sh changes. Should never happen.
# We do NOT just update config.h because that is not sufficient.
# An out of date config.h is not fatal but complains loudly!
$(PERL_INC)config.h : $(PERL_SRC)config.sh
	$(NOOP)

$(PERL_ARCHLIB)Config.pm : $(PERL_SRC)config.sh
	$(NOECHO) Write Sys$Error "$(PERL_ARCHLIB)Config.pm may be out of date with config.h or genconfig.pl"
	olddef = F$Environment("Default")
	Set Default $(PERL_SRC)
	$(MMS)],$mmsquals,);
	if ($self->{PERL_ARCHLIB} =~ m|\[-| && $self->{PERL_SRC} =~ m|(\[-+)|) {
	    my($prefix,$target) = ($1,$self->fixpath('$(PERL_ARCHLIB)Config.pm',0));
	    $target =~ s/\Q$prefix/[/;
	    push(@m," $target");
	}
	else { push(@m,' $(MMS$TARGET)'); }
	push(@m,q[
	Set Default 'olddef'
]);
    }

    push(@m, join(" ", map($self->fixpath($_,0),sort values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n")
      if %{$self->{XS}};

    join('',@m);
}


=item makeaperl (override)

Undertake to build a new set of Perl images using VMS commands.  Since
VMS does dynamic loading, it's not necessary to statically link each
extension into the Perl image, so this isn't the normal build path.
Consequently, it hasn't really been tested, and may well be incomplete.

=cut

our %olbs;  # needs to be localized

sub makeaperl {
    my($self, %attribs) = @_;
    my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmpdir, $libperl) =
      @attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)};
    my(@m);
    push @m, "
# --- MakeMaker makeaperl section ---
MAP_TARGET    = $target
";
    return join '', @m if $self->{PARENT};

    my($dir) = join ":", @{$self->{DIR}};

    unless ($self->{MAKEAPERL}) {
	push @m, q{
$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE)
	$(NOECHO) $(ECHO) "Writing ""$(MMS$TARGET)"" for this $(MAP_TARGET)"
	$(NOECHO) $(PERLRUNINST) \
		Makefile.PL DIR=}, $dir, q{ \
		FIRST_MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
		MAKEAPERL=1 NORECURS=1 };

	push @m, map(q[ \\\n\t\t"$_"], @ARGV),q{

$(MAP_TARGET) :: $(MAKE_APERL_FILE)
	$(MAKE)$(USEMAKEFILE)$(MAKE_APERL_FILE) static $(MMS$TARGET)
};
	push @m, "\n";

	return join '', @m;
    }


    my($linkcmd,@optlibs,@staticpkgs,$extralist,$targdir,$libperldir,%libseen);
    local($_);

    # The front matter of the linkcommand...
    $linkcmd = join ' ', $Config{'ld'},
	    grep($_, @Config{qw(large split ldflags ccdlflags)});
    $linkcmd =~ s/\s+/ /g;

    # Which *.olb files could we make use of...
    local(%olbs);       # XXX can this be lexical?
    $olbs{$self->{INST_ARCHAUTODIR}} = "$self->{BASEEXT}\$(LIB_EXT)";
    require File::Find;
    File::Find::find(sub {
	return unless m/\Q$self->{LIB_EXT}\E$/;
	return if m/^libperl/;

	if( exists $self->{INCLUDE_EXT} ){
		my $found = 0;

		(my $xx = $File::Find::name) =~ s,.*?/auto/,,;
		$xx =~ s,/?$_,,;
		$xx =~ s,/,::,g;

		# Throw away anything not explicitly marked for inclusion.
		# DynaLoader is implied.
		foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){
			if( $xx eq $incl ){
				$found++;
				last;
			}
		}
		return unless $found;
	}
	elsif( exists $self->{EXCLUDE_EXT} ){
		(my $xx = $File::Find::name) =~ s,.*?/auto/,,;
		$xx =~ s,/?$_,,;
		$xx =~ s,/,::,g;

		# Throw away anything explicitly marked for exclusion
		foreach my $excl (@{$self->{EXCLUDE_EXT}}){
			return if( $xx eq $excl );
		}
	}

	$olbs{$ENV{DEFAULT}} = $_;
    }, grep( -d $_, @{$searchdirs || []}));

    # We trust that what has been handed in as argument will be buildable
    $static = [] unless $static;
    @olbs{@{$static}} = (1) x @{$static};

    $extra = [] unless $extra && ref $extra eq 'ARRAY';
    # Sort the object libraries in inverse order of
    # filespec length to try to insure that dependent extensions
    # will appear before their parents, so the linker will
    # search the parent library to resolve references.
    # (e.g. Intuit::DWIM will precede Intuit, so unresolved
    # references from [.intuit.dwim]dwim.obj can be found
    # in [.intuit]intuit.olb).
    for (sort { length($a) <=> length($b) || $a cmp $b } keys %olbs) {
	next unless $olbs{$_} =~ /\Q$self->{LIB_EXT}\E$/;
	my($dir) = $self->fixpath($_,1);
	my($extralibs) = $dir . "extralibs.ld";
	my($extopt) = $dir . $olbs{$_};
	$extopt =~ s/$self->{LIB_EXT}$/.opt/;
	push @optlibs, "$dir$olbs{$_}";
	# Get external libraries this extension will need
	if (-f $extralibs ) {
	    my %seenthis;
	    open my $list, "<", $extralibs or warn $!,next;
	    while (<$list>) {
		chomp;
		# Include a library in the link only once, unless it's mentioned
		# multiple times within a single extension's options file, in which
		# case we assume the builder needed to search it again later in the
		# link.
		my $skip = exists($libseen{$_}) && !exists($seenthis{$_});
		$libseen{$_}++;  $seenthis{$_}++;
		next if $skip;
		push @$extra,$_;
	    }
	}
	# Get full name of extension for ExtUtils::Miniperl
	if (-f $extopt) {
	    open my $opt, '<', $extopt or die $!;
	    while (<$opt>) {
		next unless /(?:UNIVERSAL|VECTOR)=boot_([\w_]+)/;
		my $pkg = $1;
		$pkg =~ s#__*#::#g;
		push @staticpkgs,$pkg;
	    }
	}
    }
    # Place all of the external libraries after all of the Perl extension
    # libraries in the final link, in order to maximize the opportunity
    # for XS code from multiple extensions to resolve symbols against the
    # same external library while only including that library once.
    push @optlibs, @$extra;

    $target = "Perl$Config{'exe_ext'}" unless $target;
    my $shrtarget;
    ($shrtarget,$targdir) = fileparse($target);
    $shrtarget =~ s/^([^.]*)/$1Shr/;
    $shrtarget = $targdir . $shrtarget;
    $target = "Perlshr.$Config{'dlext'}" unless $target;
    $tmpdir = "[]" unless $tmpdir;
    $tmpdir = $self->fixpath($tmpdir,1);
    if (@optlibs) { $extralist = join(' ',@optlibs); }
    else          { $extralist = ''; }
    # Let ExtUtils::Liblist find the necessary libs for us (but skip PerlShr)
    # that's what we're building here).
    push @optlibs, grep { !/PerlShr/i } split ' ', +($self->ext())[2];
    if ($libperl) {
	unless (-f $libperl || -f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',$libperl))) {
	    print "Warning: $libperl not found\n";
	    undef $libperl;
	}
    }
    unless ($libperl) {
	if (defined $self->{PERL_SRC}) {
	    $libperl = $self->catfile($self->{PERL_SRC},"libperl$self->{LIB_EXT}");
	} elsif (-f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',"libperl$self->{LIB_EXT}")) ) {
	} else {
	    print "Warning: $libperl not found
    If you're going to build a static perl binary, make sure perl is installed
    otherwise ignore this warning\n";
	}
    }
    $libperldir = $self->fixpath((fileparse($libperl))[1],1);

    push @m, '
# Fill in the target you want to produce if it\'s not perl
MAP_TARGET    = ',$self->fixpath($target,0),'
MAP_SHRTARGET = ',$self->fixpath($shrtarget,0),"
MAP_LINKCMD   = $linkcmd
MAP_PERLINC   = ", $perlinc ? map('"$_" ',@{$perlinc}) : '',"
MAP_EXTRA     = $extralist
MAP_LIBPERL = ",$self->fixpath($libperl,0),'
';


    push @m,"\n${tmpdir}Makeaperl.Opt : \$(MAP_EXTRA)\n";
    foreach (@optlibs) {
	push @m,'	$(NOECHO) $(PERL) -e "print q{',$_,'}" >>$(MMS$TARGET)',"\n";
    }
    push @m,"\n${tmpdir}PerlShr.Opt :\n\t";
    push @m,'$(NOECHO) $(PERL) -e "print q{$(MAP_SHRTARGET)}" >$(MMS$TARGET)',"\n";

    push @m,'
$(MAP_SHRTARGET) : $(MAP_LIBPERL) Makeaperl.Opt ',"${libperldir}Perlshr_Attr.Opt",'
	$(MAP_LINKCMD)/Shareable=$(MMS$TARGET) $(MAP_LIBPERL), Makeaperl.Opt/Option ',"${libperldir}Perlshr_Attr.Opt/Option",'
$(MAP_TARGET) : $(MAP_SHRTARGET) ',"${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}PerlShr.Opt",'
	$(MAP_LINKCMD) ',"${tmpdir}perlmain\$(OBJ_EXT)",', PerlShr.Opt/Option
	$(NOECHO) $(ECHO) "To install the new ""$(MAP_TARGET)"" binary, say"
	$(NOECHO) $(ECHO) "    $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) inst_perl $(USEMACROS)MAP_TARGET=$(MAP_TARGET)$(ENDMACRO)"
	$(NOECHO) $(ECHO) "To remove the intermediate files, say
	$(NOECHO) $(ECHO) "    $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) map_clean"
';
    push @m,"\n${tmpdir}perlmain.c : \$(FIRST_MAKEFILE)\n\t\$(NOECHO) \$(PERL) -e 1 >${tmpdir}Writemain.tmp\n";
    push @m, "# More from the 255-char line length limit\n";
    foreach (@staticpkgs) {
	push @m,'	$(NOECHO) $(PERL) -e "print q{',$_,qq[}" >>${tmpdir}Writemain.tmp\n];
    }

    push @m, sprintf <<'MAKE_FRAG', $tmpdir, $tmpdir;
	$(NOECHO) $(PERL) $(MAP_PERLINC) -ane "use ExtUtils::Miniperl; writemain(@F)" %sWritemain.tmp >$(MMS$TARGET)
	$(NOECHO) $(RM_F) %sWritemain.tmp
MAKE_FRAG

    push @m, q[
# Still more from the 255-char line length limit
doc_inst_perl :
	$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
	$(NOECHO) $(ECHO) "Perl binary $(MAP_TARGET)|" >.MM_tmp
	$(NOECHO) $(ECHO) "MAP_STATIC|$(MAP_STATIC)|" >>.MM_tmp
	$(NOECHO) $(PERL) -pl040 -e " " ].$self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'),q[ >>.MM_tmp
	$(NOECHO) $(ECHO) -e "MAP_LIBPERL|$(MAP_LIBPERL)|" >>.MM_tmp
	$(NOECHO) $(DOC_INSTALL) <.MM_tmp >>].$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q[
	$(NOECHO) $(RM_F) .MM_tmp
];

    push @m, "
inst_perl : pure_inst_perl doc_inst_perl
	\$(NOECHO) \$(NOOP)

pure_inst_perl : \$(MAP_TARGET)
	$self->{CP} \$(MAP_SHRTARGET) ",$self->fixpath($Config{'installbin'},1),"
	$self->{CP} \$(MAP_TARGET) ",$self->fixpath($Config{'installbin'},1),"

clean :: map_clean
	\$(NOECHO) \$(NOOP)

map_clean :
	\$(RM_F) ${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}perlmain.c \$(FIRST_MAKEFILE)
	\$(RM_F) ${tmpdir}Makeaperl.Opt ${tmpdir}PerlShr.Opt \$(MAP_TARGET)
";

    join '', @m;
}


# --- Output postprocessing section ---

=item maketext_filter (override)

Ensure that colons marking targets are preceded by space, in order
to distinguish the target delimiter from a colon appearing as
part of a filespec.

=cut

sub maketext_filter {
    my($self, $text) = @_;

    $text =~ s/^([^\s:=]+)(:+\s)/$1 $2/mg;
    return $text;
}

=item prefixify (override)

prefixifying on VMS is simple.  Each should simply be:

    perl_root:[some.dir]

which can just be converted to:

    volume:[your.prefix.some.dir]

otherwise you get the default layout.

In effect, your search prefix is ignored and $Config{vms_prefix} is
used instead.

=cut

sub prefixify {
    my($self, $var, $sprefix, $rprefix, $default) = @_;

    # Translate $(PERLPREFIX) to a real path.
    $rprefix = $self->eliminate_macros($rprefix);
    $rprefix = vmspath($rprefix) if $rprefix;
    $sprefix = vmspath($sprefix) if $sprefix;

    $default = vmsify($default)
      unless $default =~ /\[.*\]/;

    (my $var_no_install = $var) =~ s/^install//;
    my $path = $self->{uc $var} ||
               $ExtUtils::MM_Unix::Config_Override{lc $var} ||
               $Config{lc $var} || $Config{lc $var_no_install};

    if( !$path ) {
        warn "  no Config found for $var.\n" if $Verbose >= 2;
        $path = $self->_prefixify_default($rprefix, $default);
    }
    elsif( !$self->{ARGS}{PREFIX} || !$self->file_name_is_absolute($path) ) {
        # do nothing if there's no prefix or if its relative
    }
    elsif( $sprefix eq $rprefix ) {
        warn "  no new prefix.\n" if $Verbose >= 2;
    }
    else {

        warn "  prefixify $var => $path\n"     if $Verbose >= 2;
        warn "    from $sprefix to $rprefix\n" if $Verbose >= 2;

        my($path_vol, $path_dirs) = $self->splitpath( $path );
        if( $path_vol eq $Config{vms_prefix}.':' ) {
            warn "  $Config{vms_prefix}: seen\n" if $Verbose >= 2;

            $path_dirs =~ s{^\[}{\[.} unless $path_dirs =~ m{^\[\.};
            $path = $self->_catprefix($rprefix, $path_dirs);
        }
        else {
            $path = $self->_prefixify_default($rprefix, $default);
        }
    }

    print "    now $path\n" if $Verbose >= 2;
    return $self->{uc $var} = $path;
}


sub _prefixify_default {
    my($self, $rprefix, $default) = @_;

    warn "  cannot prefix, using default.\n" if $Verbose >= 2;

    if( !$default ) {
        warn "No default!\n" if $Verbose >= 1;
        return;
    }
    if( !$rprefix ) {
        warn "No replacement prefix!\n" if $Verbose >= 1;
        return '';
    }

    return $self->_catprefix($rprefix, $default);
}

sub _catprefix {
    my($self, $rprefix, $default) = @_;

    my($rvol, $rdirs) = $self->splitpath($rprefix);
    if( $rvol ) {
        return $self->catpath($rvol,
                                   $self->catdir($rdirs, $default),
                                   ''
                                  )
    }
    else {
        return $self->catdir($rdirs, $default);
    }
}


=item cd

=cut

sub cd {
    my($self, $dir, @cmds) = @_;

    $dir = vmspath($dir);

    my $cmd = join "\n\t", map "$_", @cmds;

    # No leading tab makes it look right when embedded
    my $make_frag = sprintf <<'MAKE_FRAG', $dir, $cmd;
startdir = F$Environment("Default")
	Set Default %s
	%s
	Set Default 'startdir'
MAKE_FRAG

    # No trailing newline makes this easier to embed
    chomp $make_frag;

    return $make_frag;
}


=item oneliner

=cut

sub oneliner {
    my($self, $cmd, $switches) = @_;
    $switches = [] unless defined $switches;

    # Strip leading and trailing newlines
    $cmd =~ s{^\n+}{};
    $cmd =~ s{\n+$}{};

    my @cmds = split /\n/, $cmd;
    $cmd = join " \n\t  -e ", map $self->quote_literal($_), @cmds;
    $cmd = $self->escape_newlines($cmd);

    # Switches must be quoted else they will be lowercased.
    $switches = join ' ', map { qq{"$_"} } @$switches;

    return qq{\$(ABSPERLRUN) $switches -e $cmd "--"};
}


=item B<echo>

perl trips up on "<foo>" thinking it's an input redirect.  So we use the
native Write command instead.  Besides, it's faster.

=cut

sub echo {
    my($self, $text, $file, $opts) = @_;

    # Compatibility with old options
    if( !ref $opts ) {
        my $append = $opts;
        $opts = { append => $append || 0 };
    }
    my $opencmd = $opts->{append} ? 'Open/Append' : 'Open/Write';

    $opts->{allow_variables} = 0 unless defined $opts->{allow_variables};

    my $ql_opts = { allow_variables => $opts->{allow_variables} };

    my @cmds = ("\$(NOECHO) $opencmd MMECHOFILE $file ");
    push @cmds, map { '$(NOECHO) Write MMECHOFILE '.$self->quote_literal($_, $ql_opts) }
                split /\n/, $text;
    push @cmds, '$(NOECHO) Close MMECHOFILE';
    return @cmds;
}


=item quote_literal

=cut

sub quote_literal {
    my($self, $text, $opts) = @_;
    $opts->{allow_variables} = 1 unless defined $opts->{allow_variables};

    # I believe this is all we should need.
    $text =~ s{"}{""}g;

    $text = $opts->{allow_variables}
      ? $self->escape_dollarsigns($text) : $self->escape_all_dollarsigns($text);

    return qq{"$text"};
}

=item escape_dollarsigns

Quote, don't escape.

=cut

sub escape_dollarsigns {
    my($self, $text) = @_;

    # Quote dollar signs which are not starting a variable
    $text =~ s{\$ (?!\() }{"\$"}gx;

    return $text;
}


=item escape_all_dollarsigns

Quote, don't escape.

=cut

sub escape_all_dollarsigns {
    my($self, $text) = @_;

    # Quote dollar signs
    $text =~ s{\$}{"\$\"}gx;

    return $text;
}

=item escape_newlines

=cut

sub escape_newlines {
    my($self, $text) = @_;

    $text =~ s{\n}{-\n}g;

    return $text;
}

=item max_exec_len

256 characters.

=cut

sub max_exec_len {
    my $self = shift;

    return $self->{_MAX_EXEC_LEN} ||= 256;
}

=item init_linker

=cut

sub init_linker {
    my $self = shift;
    $self->{EXPORT_LIST} ||= '$(BASEEXT).opt';

    my $shr = $Config{dbgprefix} . 'PERLSHR';
    if ($self->{PERL_SRC}) {
        $self->{PERL_ARCHIVE} ||=
          $self->catfile($self->{PERL_SRC}, "$shr.$Config{'dlext'}");
    }
    else {
        $self->{PERL_ARCHIVE} ||=
          $ENV{$shr} ? $ENV{$shr} : "Sys\$Share:$shr.$Config{'dlext'}";
    }

    $self->{PERL_ARCHIVEDEP} ||= '';
    $self->{PERL_ARCHIVE_AFTER} ||= '';
}


=item catdir (override)

=item catfile (override)

Eliminate the macros in the output to the MMS/MMK file.

(L<File::Spec::VMS> used to do this for us, but it's being removed)

=cut

sub catdir {
    my $self = shift;

    # Process the macros on VMS MMS/MMK
    my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_  } @_;

    my $dir = $self->SUPER::catdir(@args);

    # Fix up the directory and force it to VMS format.
    $dir = $self->fixpath($dir, 1);

    return $dir;
}

sub catfile {
    my $self = shift;

    # Process the macros on VMS MMS/MMK
    my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_  } @_;

    my $file = $self->SUPER::catfile(@args);

    $file = vmsify($file);

    return $file
}


=item eliminate_macros

Expands MM[KS]/Make macros in a text string, using the contents of
identically named elements of C<%$self>, and returns the result
as a file specification in Unix syntax.

NOTE:  This is the canonical version of the method.  The version in
L<File::Spec::VMS> is deprecated.

=cut

sub eliminate_macros {
    my($self,$path) = @_;
    return '' unless $path;
    $self = {} unless ref $self;

    my($npath) = unixify($path);
    # sometimes unixify will return a string with an off-by-one trailing null
    $npath =~ s{\0$}{};

    my($complex) = 0;
    my($head,$macro,$tail);

    # perform m##g in scalar context so it acts as an iterator
    while ($npath =~ m#(.*?)\$\((\S+?)\)(.*)#gs) {
        if (defined $self->{$2}) {
            ($head,$macro,$tail) = ($1,$2,$3);
            if (ref $self->{$macro}) {
                if (ref $self->{$macro} eq 'ARRAY') {
                    $macro = join ' ', @{$self->{$macro}};
                }
                else {
                    print "Note: can't expand macro \$($macro) containing ",ref($self->{$macro}),
                          "\n\t(using MMK-specific deferred substitutuon; MMS will break)\n";
                    $macro = "\cB$macro\cB";
                    $complex = 1;
                }
            }
            else {
                $macro = $self->{$macro};
                # Don't unixify if there is unescaped whitespace
                $macro = unixify($macro) unless ($macro =~ /(?<!\^)\s/);
                $macro =~ s#/\Z(?!\n)##;
            }
            $npath = "$head$macro$tail";
        }
    }
    if ($complex) { $npath =~ s#\cB(.*?)\cB#\${$1}#gs; }
    $npath;
}

=item fixpath

   my $path = $mm->fixpath($path);
   my $path = $mm->fixpath($path, $is_dir);

Catchall routine to clean up problem MM[SK]/Make macros.  Expands macros
in any directory specification, in order to avoid juxtaposing two
VMS-syntax directories when MM[SK] is run.  Also expands expressions which
are all macro, so that we can tell how long the expansion is, and avoid
overrunning DCL's command buffer when MM[KS] is running.

fixpath() checks to see whether the result matches the name of a
directory in the current default directory and returns a directory or
file specification accordingly.  C<$is_dir> can be set to true to
force fixpath() to consider the path to be a directory or false to force
it to be a file.

NOTE:  This is the canonical version of the method.  The version in
L<File::Spec::VMS> is deprecated.

=cut

sub fixpath {
    my($self,$path,$force_path) = @_;
    return '' unless $path;
    $self = bless {}, $self unless ref $self;
    my($fixedpath,$prefix,$name);

    if ($path =~ m#^\$\([^\)]+\)\Z(?!\n)#s || $path =~ m#[/:>\]]#) {
        if ($force_path or $path =~ /(?:DIR\)|\])\Z(?!\n)/) {
            $fixedpath = vmspath($self->eliminate_macros($path));
        }
        else {
            $fixedpath = vmsify($self->eliminate_macros($path));
        }
    }
    elsif ((($prefix,$name) = ($path =~ m#^\$\(([^\)]+)\)(.+)#s)) && $self->{$prefix}) {
        my($vmspre) = $self->eliminate_macros("\$($prefix)");
        # is it a dir or just a name?
        $vmspre = ($vmspre =~ m|/| or $prefix =~ /DIR\Z(?!\n)/) ? vmspath($vmspre) : '';
        $fixedpath = ($vmspre ? $vmspre : $self->{$prefix}) . $name;
        $fixedpath = vmspath($fixedpath) if $force_path;
    }
    else {
        $fixedpath = $path;
        $fixedpath = vmspath($fixedpath) if $force_path;
    }
    # No hints, so we try to guess
    if (!defined($force_path) and $fixedpath !~ /[:>(.\]]/) {
        $fixedpath = vmspath($fixedpath) if -d $fixedpath;
    }

    # Trim off root dirname if it's had other dirs inserted in front of it.
    $fixedpath =~ s/\.000000([\]>])/$1/;
    # Special case for VMS absolute directory specs: these will have had device
    # prepended during trip through Unix syntax in eliminate_macros(), since
    # Unix syntax has no way to express "absolute from the top of this device's
    # directory tree".
    if ($path =~ /^[\[>][^.\-]/) { $fixedpath =~ s/^[^\[<]+//; }

    return $fixedpath;
}


=item os_flavor

VMS is VMS.

=cut

sub os_flavor {
    return('VMS');
}


=item is_make_type (override)

None of the make types being checked for is viable on VMS,
plus our $self->{MAKE} is an unexpanded (and unexpandable)
macro whose value is known only to the make utility itself.

=cut

sub is_make_type {
    my($self, $type) = @_;
    return 0;
}


=item make_type (override)

Returns a suitable string describing the type of makefile being written.

=cut

sub make_type { "$Config{make}-style"; }


=back


=head1 AUTHOR

Original author Charles Bailey F<bailey@newman.upenn.edu>

Maintained by Michael G Schwern F<schwern@pobox.com>

See L<ExtUtils::MakeMaker> for patching and contact information.


=cut

1;

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         taste Alt
Choices-ru.utf-8: Раскладка клавиатуры по умолчанию, нет клавиши AltGr, правый Alt (AltGr), правый Control, правая клавиша с логотипом, клавиша с меню, левый Alt, левая клавиша с логотипом, Enter на цифр. клавиатуре, обе клавиши с логотипом, обе клавиши Alt одновременно
Choices-si.utf-8: යතුරුපුවරු ආකෘතිය සඳහා සම්මතය, AltGr යතුරක් නැත, දකුණු Alt (AltGr), දකුණු Control, දකුණු ලාංඡය යතුර, මෙනු යතුර, වම් Alt, වම් ලාංඡන යතුර, අංක පුවරුවේ Enter යතුර, ලෝගෝ යතුරු දෙකම, Alt යතුරු දෙකම
Choices-sk.utf-8: Predvolené rozloženie klávesnice, Žiaden kláves Alt, Pravý Alt (AltGr), Pravý Control, Pravý kláves Logo, Kláves Menu, Ľavý Alt, Ľavý kláves Logo, Kláves Enter na numerickej klávesnici, Oba klávesy Logo, Oba klávesy Alt
Choices-sl.utf-8: Privzeta postavitev tipkovnice, Brez Desne izmenjalke, Desna izmenjalka (AltGR), Desna krmilka (Control), Desna tipka z znakom, Menijska tipka, Leva izmenjalka (Alt), Leva tipka z znakom, Vnašalka na številski tipkovnici, Obe tipki z znakom, Obe izmenjalki
Choices-sq.utf-8: Gjëndja fillestare për shtrirjen e tastierës, Nuk ka asnjë tast AltGr, Alt e djathtë (AltGr), Kontroll i Djathtë, Logo key i djathtë, Çelësi i menysë, Alt e Majtë, Logo key i Majtë, Tasti Enter, Të dy çelësat Logo, Të dy tastet Alt
Choices-sr.utf-8: Подразумевани распоред тастатуре, Нема AltGr тастера, Десни Alt (AltGr), Десни Control, Десни лого тастер, Мени тастер, Леви Alt, Леви лого тастер, Тастер Enter на нумеричкој тастатури, Оба лого тастера, Оба Alt тастера
Choices-sr@latin.utf-8: Podrazumevani raspored tastature, Nema AltGr tastera, Desni Alt (AltGr), Desni Control, Desni logo taster, Meni taster, Levi Alt, Levi logo taster, Taster Enter na numeričkoj tastaturi, Oba logo tastera, Oba Alt tastera
Choices-sv.utf-8: Standardvärdet för tangentbordslayouten, Ingen AltGr-tangent, Alt\, höger (AltGr), Control\, höger, Tangent med logotyp\, höger, Menyknapp, Alt\, vänster, Tangent med logotyp\, vänster, Enter på numeriskt tangentbord, Båda tangenterna med logotype, Båda Alt-tangenterna
Choices-ta.utf-8: முன்னிருப்பு விசைப்பலகை இடஅமைவு, AltGr விசை இல்லை, வலது ஆல்ட் (AltGr), வலது கன்ட்ரோல், வலது லோகோ விசை, மெனு விசை, இடது ஆல்ட், இடது லோகோ விசை, விசை பலக உள்ளீடு, இரண்டு லோகோ விசைகளும், இரண்டு ஆல்ட் விசைகளும்
Choices-te.utf-8: ఒక కీబోర్డు లేఔటు  ఎంచుకోకపోతే  తీసుకొనేది, AltGr కీ లేదు, కుడి ఆల్ట్ (AltGr), కుడి కంట్రోల్, కుడి బొమ్మ కీ, మెనూ కీ, ఎడమ ఆల్ట్, ఎడమ బొమ్మ కీ, కీపాడ్ ఎంటర్ కీ, రెండు బొమ్మ(లోగో) కీలు, రెండు ఆల్ట్ కీలు
Choices-tg.utf-8: Тарҳбандии пешфарз барои ҳарфкалид, Бе тугмаи AltGr, Alt-и рост (AltGr), Control-и рост, Тугмаи рости тамға, Тугмаи меню, Alt-и чап, Тугмаи чапи тамға, Тугмаи Enter дар ҳарфкалиди рақамӣ, Ҳар дуи тугмаи тамға, Ҳар дуи тугмаи Alt
Choices-th.utf-8: ค่าปริยายของผังแป้นพิมพ์, ไม่ใช้ปุ่ม AltGr, Alt ขวา (AltGr), Control ขวา, ปุ่มโลโก้ขวา, ปุ่มเมนู, Alt ซ้าย, ปุ่มโลโก้ซ้าย, ปุ่ม Enter ในแป้นตัวเลข, ปุ่มโลโก้คู่, ปุ่ม Alt คู่
Choices-tr.utf-8: Öntanımlı klavye düzeni, AltGr tuşu yok, Sağ Alt (AltGr), Sağ Control, Sağ Logo tuşu, Menü tuşu, Sol Alt, Sol Logo tuşu, Tuş takımı Enter tuşu, Her iki Logo tuşu, Her iki Alt tuşu
Choices-ug.utf-8: ھەرپتاختا جايلاشتۇرۇشنىڭ كۆڭۈلدىكى قىممىتى, AltGr كۇنۇپكا يوق, ئوڭ Alt (AltGr), ئوڭ Control, ئوڭ  Logo كۇنۇپكا, تىزىملىك كۇنۇپكا, سول Alt, سول Logo كۇنۇپكا, كىچىك ھەرپتاختا Enter كۇنۇپكىسى, ئىككى Logo كۇنۇپكىسى, ئىككى Alt كۇنۇپكىسى
Choices-uk.utf-8: Звична для даної розкладки клавіатури, Не AltGr клавіша, Правий Alt (AltGr), Правий Control, Права клавіша Logo, Клавіша Menu, Лівий Alt, Ліва клавіша Logo, Клавіша Enter на цифровій клавіатурі, Обидві клавіші Logo, Обидві клавіші Alt
Choices-vi.utf-8: Giá trị mặc định cho bố trí bàn phím, Không có phím AltGr, Alt phải (AltGr), Ctrl phải, Phím Win phải, Phím trình đơn, Alt trái, Phím Win trái, Phím Gõ Vùng Phím, Cả hai khóa Logo, Cả hai phím Alt
Choices-zh_cn.utf-8: 键盘布局默认值, 无 AltGr 键, 右 Alt 键 (AltGr), 右 Control 键, 右徽标键, 菜单键, 左 Alt, 左徽标键, 小键盘回车键, 两个徽标键, 两个 Alt 键
Choices-zh_tw.utf-8: 鍵盤排列方式的預設值, 沒有 AltGr 鍵, 左 Alt (AltGr), 右 Control, 右 Logo 鍵, Menu 鍵, 左 Alt, 左 Logo 鍵, 數字區的 Enter 鍵, 兩邊的 Logo 鍵, 兩邊的 Alt 鍵
Default: Right Alt (AltGr)
Description: Key to function as AltGr:
Description-ar.utf-8: المفتاح المطلوب استخدامه كمفتاح AltGr:
Description-ast.utf-8: Tecla pa la función AltGr:
Description-be.utf-8: Кнопка, якая будзе працаваць як AltGr:
Description-bg.utf-8: Клавиш, използван като AltGr:
Description-bn.utf-8: AltGr এর মত কাজের জন্য কী:
Description-bo.utf-8: AltGr སྤྱོད་ནུས་ཡོད་པའི་མཐེབ：
Description-bs.utf-8: Tipka s funkcijom AltGr:
Description-ca.utf-8: Tecla per a fer de AltGr:
Description-cs.utf-8: Klávesa pro funkci AltGr:
Description-cy.utf-8: Bysell i weithredu fel AltGr:
Description-da.utf-8: Tast, der fungerer som AltGr:
Description-de.utf-8: Taste, die als AltGr fungieren soll:
Description-dz.utf-8: AltGr སྦེ་ལཱ་འབད་ནིའི་ལྡེ་ཡིག:
Description-el.utf-8: Πλήκτρο για λειτουργία ως AltGr:
Description-eo.utf-8: Klavo por funkcii kiel AltGr:
Description-es.utf-8: Tecla a utilizar para AltGr:
Description-et.utf-8: Klahv, mida kasutada AltGr klahvina:
Description-eu.utf-8: AltGr funtzioa egiteko tekla:
Description-fa.utf-8: کلیدی که مانند AltGr عمل کند:
Description-fi.utf-8: AltGr-näppäimenä toimiva näppäin:
Description-fr.utf-8: Touche destinée à se substituer à AltGr :
Description-ga.utf-8: Eochair le húsáid mar AltGr:
Description-gl.utf-8: Tecla a usar como AltGr:
Description-gu.utf-8: AltGr તરીકે કાર્ય કરવા માટેની કળ:
Description-he.utf-8: מקש לשימוש כ־AltGr:
Description-hi.utf-8: ऑल्ट-जीआर (AltGr) का स्थान लेने वाली कुंजी:
Description-hr.utf-8: Tipka koja će raditi kao AltGr:
Description-hu.utf-8: AltGr-ként működő billentyű:
Description-id.utf-8: Tombol untuk AltGr:
Description-is.utf-8: Lykill sem á að virka sem AltGr:
Description-it.utf-8: Tasto da usare come Alt destro:
Description-ja.utf-8: AltGr として機能させるキー:
Description-kab.utf-8: Taqeffalt ara yeddun am AltGr:
Description-kk.utf-8: AltGr үшін перне:
Description-km.utf-8: គ្រាប់ចុច​​ត្រូវ​កំណត់​មុខងារ​ជា AltGr ៖
Description-kn.utf-8: AltGr ಆಗಿ ಕಾರ್ಯ ನಿರ್ವಹಿಸುವ ಕೀಲಿ:
Description-ko.utf-8: AltGr 키로 동작할 키:
Description-ku.utf-8: Kilîla fonksiyonê wekî AltGr:
Description-lo.utf-8: ກະແຈສຳຄັນໃນການໃຊ້ງານເປັນ AltGr:
Description-lt.utf-8: Lyg3 funkciją atliksiantis klavišas:
Description-lv.utf-8: Taustiņš, kas kalpos kā AltGr:
Description-mk.utf-8: Копче со функција како AltGr:
Description-ml.utf-8: ആള്‍ട്ട്ജിആര്‍ കീ ആയി പ്രവര്‍ത്തിയ്ക്കേണ്ട കീ:
Description-mr.utf-8: AltGr म्हणून कार्य करण्यासाठीची कळ:
Description-nb.utf-8: Tast som skal fungere som AltGr:
Description-nl.utf-8: Toets om te functioneren als AltGr:
Description-nn.utf-8: Tast som skal verka som AltGr-tast:
Description-no.utf-8: Tast som skal fungere som AltGr:
Description-oc.utf-8: Tòca destinada a se substituir a AltGr :
Description-pa.utf-8: ਸਵਿੱਚ AltGr ਵਾਂਗ ਕੰਮ ਕਰੇਗੀ:
Description-pl.utf-8: Klawisz który ma działać jak AltGr:
Description-pt.utf-8: Tecla para funcionar como AltGr:
Description-pt_br.utf-8: Tecla para funcionar como AltGr:
Description-ro.utf-8: Tasta care funcționează ca AltGr:
Description-ru.utf-8: Клавиша, используемая как AltGr:
Description-si.utf-8: AltGr ලෙස ක්‍රියාකරන යතුර:
Description-sk.utf-8: Kláves, ktorý má fungovať ako AltGr:
Description-sl.utf-8: Tipka, ki naj deluje kot desna izmenjalka:
Description-sq.utf-8: Tasti që do të funksionoj si AltGr
Description-sr.utf-8: Тастер за AltGr функцију:
Description-sr@latin.utf-8: Taster za AltGr funkciju:
Description-sv.utf-8: Tangent att fungera som AltGr:
Description-ta.utf-8: AltGr ஆக செயல்பட வேண்டிய விசை:
Description-te.utf-8: AltGr గా పనిచేయటకు కీ:
Description-tg.utf-8: Тугмае, ки ҳамчун AltGr амал мекунад:
Description-th.utf-8: ปุ่มที่จะใช้เป็น AltGr:
Description-tr.utf-8: AltGR olarak işlev görecek olan tuş:
Description-ug.utf-8: AltGr ئىقتىدارى سۈپىتىدىكى كۇنۇپكا:
Description-uk.utf-8: Клавіша з функцією AltGr:
Description-vi.utf-8: Phím để dùng thay cho AltGr:
Description-zh_cn.utf-8: 作为 AltGr 的键：
Description-zh_tw.utf-8: 做為 AltGr 的鍵:
Extended_description: With some keyboard layouts, AltGr is a modifier key used to input some characters, primarily ones that are unusual for the language of the keyboard layout, such as foreign currency symbols and accented letters. These are often printed as an extra symbol on keys.
Extended_description-ar.utf-8: ببعض مخططات لوحات المفاتيح، يكون مفتاح AltGr مفتاح التعديل المستخدم لإدخال بعض الحروف، بالأخص تلك التي ليست متوفرة في تخطيط اللغة للوحة المفاتيح، كرموز العملات والأحرف اللاتينية المشكّلة. تكون هذه الرموز عادة مطبوعة كرموز إضافية على المفاتيح.
Extended_description-ast.utf-8: Con dalgunes disposiciones de tecláu, AltGr ye una tecla camudadora que s'usa pa introducir dalgunos caráuteres, principalmente aquellos que son inusuales pa la llingua de la distribución del tecláu, como símbolos de moneda extranxera y lletres acentuaes. Estes suelen amosase como un símbolu estra nes tecles.
Extended_description-be.utf-8: У некаторах клавіятурных раскладках AltGr - кнопка-мадыфікатар для ўводу пэўных знакаў, што адсутнічаюць у мове клавіятурнай раскладкі: напрыклад, знакі іншаземнай валюты і літары з націскамі. Яны звычайна надрукаваны як дадатковы сімвал на клавішах.
Extended_description-bg.utf-8: При някои клавиатурни подредби клавишът AltGr e модификатор, който се използва за въвеждането на някои знаци, предимно такива, които са необичайни за езика на клавиатурната подредба, като знаци за различни парични единици и букви с диакритични знаци.  Тези знаци често са изрисувани като допълнителни символи на клавишите.
Extended_description-bn.utf-8: কিছু কীবোর্ড লেআউটে AltGr একটি মডিফায়ার কী যা ব্যবহার হয় কিছু ক্যারেক্টার ইনপুট দিতে, সাধারণত যেগুলো কীবোর্ডের লেআউটে থাকেনা, যেমন বিদেশী টাকার চিহ্ন ও বিশেষ অক্ষর। এগুলোপ্রায়ই কী-র উপর অতিরিক্ত চিহ্ন হিসেবে প্রিন্ট করা থাকে।
Extended_description-bo.utf-8: མཐེབ་གཞོང་འགའ་ཞིག་གི་ཐོག་ཏུ་AltGr མཐེབ་ནི་སྐད་རིགས་ཀྱི་མཐེབ་གཞོང་ལ་ཐུན་མོང་མིན་པའི་ཡི་གེ་འཇུག་པར་སྤྱོད་པ དཔེར་ན་ཕྱི་རྒྱལ་གྱི་དངུལ་ལོའི་རྟགས་དང་ཡུལ་སྐད་དབྱེ་བྱེད་ཀྱི་ཡི་གེ་ལྟ་བུ འདི་དག་ནི་མཐེབ་ཐོག་ཏུ་ཟུར་སྣོན་གྱི་རྟགས་ཀྱི་ཚུལ་དུ་པར་འདེབས་བྱས་ཡོད
Extended_description-bs.utf-8: Kod nekih rasporeda tastature, AltGr je modifikaciona tipka za unos određenih karaktera, uglavnom onih koji su neobični za jezik rasporeda tastature, poput simbola stranih valuta i slova sa akcentima. Ovi simboli su obično dopisani posebno na tipkama.
Extended_description-ca.utf-8: En algunes disposicions, AltGr és una tecla de modificació que s'empra per a introduir alguns caràcters, generalment alguns que són inusuals per a la llengua de la disposició del teclat, com poden ser símbols de divises estrangeres i lletres accentuades. Aquests són freqüentment impresos com símbols extra a les tecles.
Extended_description-cs.utf-8: V některých klávesových rozloženích se modifikátor AltGr používá pro zadávání některých znaků, hlavně těch, které jsou pro daný jazyk neobvyklé, jako jsou cizí symboly měn nebo akcentovaná písmena. Tyto jsou obvykle vytištěny na klávesách jako další symbol (často odlišnou barvou).
Extended_description-cy.utf-8: Ar rhai cynlluniau bysellfwrdd, defnyddir AltGr fel bysell addasydd i deipio rhai nodau, yn bennaf rhai sydd yn anghyffredin i iaith y cynllun bysellfwrdd, fel symbolau arian tramor a llythrennau acennog. Yn aml mae'r rhain wedi eu argraffu fel symbol ychwanegol ar fysellau.
Extended_description-da.utf-8: I nogle tastaturlayouts er AltGr en ændringstast, der bliver brugt til at indtaste visse tegn, primært de der er usædvanlige for tastaturlayoutets sprog. Det kan være symboler for fremmed valuta og accentuerede bogstaver.
Extended_description-de.utf-8: Bei manchen Tastaturbelegungen ist AltGr eine Modifikatortaste, die zur Eingabe einiger Zeichen verwendet wird. Hauptsächlich wird sie für solche Zeichen verwendet, die für die Sprache der Tastatur ungewöhnlich sind, wie ausländische Währungssymbole und akzentuierte Buchstaben. Diese werden oft als Extrasymbol auf die Tasten gedruckt.
Extended_description-dz.utf-8: ལྡེ་སྒྲོམ་སྒྲིག་བཀོད་ལ་ལོ་ཅིག་དང་གཅིག་ཁར་ AltGr འདི་ ལེགས་བཅོས་ལྡེ་ཡིག་ཨིནམ་དང་ དེ་ཡང་ གཙོ་བོ་ར་ ཨ་རྟག་དང་མ་འདྲ་བའི་ལྡེ་སྒྲོམ་སྒྲིག་བཀོད་སྐད་ཡིག་ དཔེར་ན་ ཕྱི་དངུལ་བརྡ་མཚོན་དང་སྒྲ་གདངས་ཅན་གྱི་ཡི་གུའི་རིགས་ཚུ་ཨིན་པུཊི་འབད་ནི་གི་དོན་ལུ་ལག་ལེན་འཐབ་དོ་ཡོདཔ་ཨིན། དེ་ཚུ་ འཕྲལ་འཕྲལ་ར་ ལྡེ་སྒྲོམ་གུ་བརྡ་མཚོན་ཐེབས་སྦེ་བཀོད་དོ་ཡོདཔ་ཨིན།
Extended_description-el.utf-8: Με μερικές διατάξεις πληκτρολογίου, το πλήκτρο AltGr χρησιμοποιείται ως πλήκτρο-μεταβολέας για την εισαγωγή μερικών χαρακτήρων, κυρίως κάποιων ασυνήθιστων για την γλώσσα που αντιστοιχεί στη διάταξη αυτή, για παράδειγμα σύμβολα ξένων νομισμάτων και γράμματα με διάφορους τόνους. Αυτά τυπώνονται συνήθως πάνω στα πλήκτρα σαν επιπλέον σύμβολα.
Extended_description-eo.utf-8: En kelkaj klavar-aranĝoj, AltGr estas modifilo-klavo uzata por enigi kelkajn signojn, principe tiuj neordinaraj por la lingvo de la klavar-aranĝo, kiel fremdaj valut-simboloj kaj supersignitaj literoj. Tiuj signoj ofte estas printitaj kiel kroman simbolon sur la klavoj.
Extended_description-es.utf-8: Con algunas distribuciones de teclados, AltGr es una tecla modificadora que se utiliza para introducir algunos caracteres, principalmente aquellos que no son usuales para el idioma de la distribución del teclado, tales como símbolos de monedas extranjeras y letras acentuadas. Éstas normalmente se muestran como un símbolo extra en las teclas.
Extended_description-et.utf-8: Mõnede klaviatuuripaigutuste korral on AltGr muuteklahv mõnede selles keeles või sel klaviatuuri harvaesinevate märkide sisestamiseks, nagu seda on välismaised valuutamärgid ja rõhumärkidega tähed. Need märgid on tihti ka klaviatuurile trükitud lisamärkidena.
Extended_description-eu.utf-8: Teklatuaren diseinu batzuetan, AltGr tekla eraldatzaile bat da zenbait karaktere idazteko, nagusiki teklatuaren diseinuan gutxitan erabiltzen direnak, hala nola atzerriko dibisa ikurrak eta azentuak. Tekla batek hirugarren ikur bat badu AltGR sakatzean ikur hori idazteko modua izan ohi da.
Extended_description-fa.utf-8: در برخی از صفحه کلید ها کلید AltGr یک کلید کمکی برای وارد کردن برخی کاراکتر هاست، که برای طرح بندی صفحه کلید آن زبان غیر معمول است. برای نمونه می توان به نماد های واحد پول و حروف مربوط به تلفظ اشاره کرد. این ها اعلب به صورت نماد های اضافه در کنار دیگر حروف دیگر چاپ شده اند.
Extended_description-fi.utf-8: Joissain näppäinasetteluissa AltGr on muuntonäppäin, jonka avulla voidaan syöttää joitain merkkejä. Nämä on yleensä näppäinasettelun kielelle epätyypillisiä, kuten ulkomaisia valuuttasymboleita ja aksentoituja kirjaimia. Nämä merkit on usein merkitty ylimääräisenä symbolina näppäimiin.
Extended_description-fr.utf-8: Avec certaines dispositions de claviers, AltGr est une touche de modification utilisée pour entrer de nombreux caractères, principalement ceux qui n'appartiennent pas à la langue correspondant à la disposition du clavier, comme les symboles des devises étrangères et les lettres accentuées. Ces caractères sont généralement indiqués sous forme de symboles supplémentaires sur les touches.
Extended_description-ga.utf-8: Le roinnt leaganacha amach, is eochair mhionathraithe é AltGr a úsáidtear chun litreacha áirithe a chlóscríobh, go háirithe litreacha nach bhfuil coitianta i dteanga leagan amach an mhéarchláir, mar shampla siombailí airgeadra eachtraigh agus litreacha le síntí fada. Go minic, tá na carachtair seo priontáilte mar shiombail bhreise ar na heochracha.
Extended_description-gl.utf-8: Con algunhas das disposicións de teclado, Alt Gr é unha tecla modificadora que se emprega para introducir algúns caracteres; principalmente algúns pouco habituais para o idioma da disposición de teclado, como símbolos de moedas estranxeiras ou letras acentuadas. Estes símbolos xeralmente están impresos nas teclas.
Extended_description-gu.utf-8: કેટલાક કીબોર્ડ દેખાવની સાથે, AltGr બદલાવ કળ કેટલાક અક્ષરો દાખલ કરવા માટે વપરાય છે, મોટાભાગે જેઓ કીબોર્ડની ભાષા માટે અસામાન્ય હોય છે, દાખલા તરીકે વિદેશી ચલણ સંજ્ઞા અને એસેન્ટ અક્ષરો. આ મોટોભાગે કળો પર વધારાની સંજ્ઞા તરીકે છાપેલ હોય છે.
Extended_description-he.utf-8: בחלק מפריסות המקלדת, נעשה שימוש במקש ההחלפה AltGr לצורך הקלדה של כל מיני תווים, בעיקר כאלו הזרים לפריסת המקלדת כגון סימני מטבע זרים ואותיות עם סימנים דיאקריטיים. אלו לרוב מודפסים כסמל נוסף על המקשים.
Extended_description-hi.utf-8: कुछ कुंजीपटल अभिन्यासों के साथ, ऑल्टजीआर "modifier" है, जिसके द्वाराकुछ अक्षर लिखे जा सकते हैं, साधारणतः वह अक्षर जिनका अधिक उपयोग उस कुंजीपटल के भाषामें न हों; उदारानातः विदेशी मुद्राओं का चिह्न एवं विशेष अक्षर. ये ज़्यादातर कुंजीपटल परअन्य अक्षरों के रूप में दिखते हैं.
Extended_description-hr.utf-8: Kod pojedinih rasporeda tipkovnice, AltGr je tipka promjene koja se koristi za upis nekih znakova, prvenstveno onih koji nisu uobičajeni za jezik rasporeda tipkovnice, kao što su simboli za stranu valutu i naglašena slova. Obično su ispisani kao dodatni simboli na tipkama.
Extended_description-hu.utf-8: Egyes billentyűzetkiosztásokon az AltGr egy olyan módosító billentyű, amely főként olyan karakterek bevitelére használható,amelyek szokatlanok a kiosztás nyelvén, például idegen pénzjelek és ékezetes betűk. Ezek gyakran extra jelekként vannak a billentyűkön feltüntetve.
Extended_description-id.utf-8: Pada beberapa pola keyboard, AltGr digunakan untuk mengetik beberapa aksara, terutama aksara tak biasa dari bahasa pada pola keyboard, seperti simbol mata uang asing dan aksara beraksen. Aksara-aksara ini seringkali tersedia sebagai simbol tambahan pada tombol.
Extended_description-is.utf-8: Í sumum lyklaborðsframsetningum er AltGr notaður sem breytilykill til innsetningar stöfum, aðallega stöfum sem eru óalgengir í tungumálinu sem tilheyrir viðkomandi lyklaborðsframsetningu, t.d. erlend gjaldmiðlatákn og ýmsir broddstafir. Í sumum tilfellum eru þessir stafir prentuaðir sem aukatákn á lyklana.
Extended_description-it.utf-8: Con alcune disposizioni di tastiera, il tasto AltGr è un tasto modificatore usato per inserire determinati caratteri (essenzialmente quelli inusuali per la lingua corrispondente alla disposizione della tastiera) come, per esempio, simboli di monete straniere e lettere con le dieresi. Questi vengono spesso mostrati come simboli addizionali sui tasti.
Extended_description-ja.utf-8: いくつかのキーボード配置においては、AltGr は、外国の通貨文字やアクセント文字のように本来キーボード配置の言語では使われないいくつかの文字を入力するのに使われる修飾キーです。これらはたいてい、キーに追加文字として印字されています。
Extended_description-kab.utf-8: Akked kra n tneɣrufin n unasiw, AltGr d taqeffalt n ubeddel tettuseqdac i usekcem n kra n yisekkilen, deg tazwara tid-nni ur neggit ara i tutlayt n tneɣruft n unasiw, am yizamulen n tedrimt tabaṛṛanit d yisekkilen s ufeskil. Zgant ttusiggzent d izamulen-nniḍen ɣef tsura.
Extended_description-kk.utf-8: Кейбір пернетақта жаймаларымен, түрлендіргіш ретінде AltGr, кейбір таңбаларды енгізу үшін қолданылады, көбінесе, ағымдағы пернетақта жаймасының тілінде жоқ таңбалар, мысалы, шетел ақша таңбалары сияқты.
Extended_description-km.utf-8: With some keyboard layouts, AltGr is a modifier key used to input some characters, primarily ones that are unusual for the language of the keyboard layout, such as foreign currency symbols and accented letters. These are often printed as an extra symbol on keys.
Extended_description-kn.utf-8: ಕೆಲವು ಕೀಲಿಮಣೆ ವಿನ್ಯಾಸಗಳಲ್ಲಿ ಕೆಲವು ಅಕ್ಷರಗಳನ್ನು ದಾಖಲಿಸಲು AltGr ಅನ್ನು ಪರಿವರ್ತಕ ಕೀಲಿಯಾಗಿ ಬಳಸಲಾಗುತ್ತದೆ, ಮುಖ್ಯವಾಗಿ ಕೀಲಿಮಣೆ ವಿನ್ಯಾಸದ ಭಾಷೆಗೆ ಅಸಾಮಾನ್ಯವಾದ ಅಕ್ಷರಗಳು, ಉದಾಹರಣೆಗೆ ವಿದೇಶಿ ಹಣದ ಚಿಹ್ನೆಗಳು ಮತ್ತು ಉಚ್ಛರಣಾ ಚಿಹ್ನೆಗಳು. ಇವುಗಳು ಸಾಮಾನ್ಯವಾಗಿ ಕೀಲಿಗಳು ಹೆಚ್ಚುವರಿ ಚಿಹ್ನೆಗಳಾಗಿ ಮುದ್ರಿಸಲಾಗುತ್ತದೆ.
Extended_description-ko.utf-8: 몇몇 키보드 배치에서 AltGr 키는, 화폐 기호나 액센트가 들어간 문자 따위처럼 해당 언어에서 자주 쓰이지 않는 문자를 입력하는데 사용합니다. 이런 문자는 키의 추가 기호로 인쇄되어 있기도 합니다.
Extended_description-ku.utf-8: Bi hin cureyên klavyeyan, AltGr ji bo nivîsandina hin curenivîsan tê bikaranîn.
Extended_description-lo.utf-8: ບາງລາຍການໂຄງຮ່າງແປ້ນພິມ AltGr ເປັນກະແຈທີ່ສຳຄັນທີ່ໃຊ້ໃນການປັບປຸງໃສ່ອັກຄະລະບາງໂຕຫລັກຄົນທີ່ຜິດປົກກະຕິສສຳຫລັບພາສາຂອງຜັງແປ້ນພິມເຊັ່ນລັກສະນະສະກຸນເງີນຕ່າງປະເທດແລະໂຕອັກສອນເນັ້ນສຽງເຫລົ່ານີ້ຈະຖືກພິມມັກຈະເປັນລັກສະນະພິເສດເທິງແປ້ນ
Extended_description-lt.utf-8: Kai kuriuose klaviatūros išdėstymuose naudojamas klavišas Lyg3 (AltGr), skirtas įvesti rečiau naudojamiems simboliams – užsienio valiutų ženklams, raidėms su diakritikais ir pan. Paprastai tokie simboliai atspausdinami ant klaviatūros papildomoje vietoje.
Extended_description-lv.utf-8: Dažos tastatūru izkārtojumos AltGr tiek lietots kā modifikācijas taustiņš, lai ievadītu dažus burtus, parasti tie neparastie burti un simboli, kā piemēram ārzemju valūtu simboli un akcentēties burti (piemēram, latviešu burti ar garumzīmēm). Bieži tie tiek attēloti uz tastatūras kā papildu simboli uz taustiņiem.
Extended_description-mk.utf-8: Кај некои распореди на тастатура, AltGr е копче за модификација кое се користи за внес на знаци кои се невообичаени за јазикот на распоредот на тастатурата, како странски валути и акцентирани букви. Тие се најчесто испишани како дополнителен симбол на копчето.
Extended_description-ml.utf-8: ചില കീബോര്‍ഡ് വ്യന്യാസത്തില്‍, AltGr കീ ചില അക്ഷരങ്ങള്‍ കൊടുക്കാന്‍ ഉപയോഗിക്കുന്നു, പ്രത്യേകിച്ച് സാധാരണ കീബോര്‍ഡിലുള്ള ഭാഷയല്ലാതെയുള്ളതോ വേറേ അക്ഷരങ്ങളോ കൊടുക്കാന്‍ ഉപയോഗിക്കുന്നു. കീകളില്‍ അധികമായ ഒരു ചിഹ്നമായാണ് അത് ഉണ്ടാകുക.
Extended_description-mr.utf-8: परकीय चलनांची चिन्हे व जोर देण्याची अक्षरे यांसारखे कळफलक आराखड्याच्या भाषेत नसणारे वर्ण टाईप करण्यासाठी, काही कळफलक आराखड्यांमध्ये AltGr ही बदलाव कळ वापरली जाते. बहुतेकदा हे वर्ण अतिरिक्त चिन्हांच्या स्वरूपात कळींवर छापलेले असतात.
Extended_description-nb.utf-8: I noen tastaturutforminger er AltGr en modifiseringstast som brukes for å skrive noen tegn, primært de som er uvanlig for språket i tastaturutformingen, som utenlandske valutasymbol og aksenttegn. Disse vises ofte som et ekstra symbol på tastene.
Extended_description-nl.utf-8: Bij sommige toetsenborden is AltGr een aanpassingstoets nodig om sommige karakters in te voeren, voornamelijk die die ongewoon zijn voor de taal van de toetsenbordindeling (zoals b.v. buitenlandse valutasymbolen, en letters met accenten). Deze staan vaak als een extra symbool op de toetsen afgedrukt.
Extended_description-nn.utf-8: På nokre tastatur er AltGr ein endringstast som vert brukt for å skriva inn spesielle teikn, som oftast teikn som er uvanlege i det språket tastaturet er sett opp for. Dette kan vera valutasymbol for andre språk, aksentteikn og liknande. Desse er ofte merkte med eit ekstra symbol på tastane.
Extended_description-no.utf-8: I noen tastaturutforminger er AltGr en modifiseringstast som brukes for å skrive noen tegn, primært de som er uvanlig for språket i tastaturutformingen, som utenlandske valutasymbol og aksenttegn. Disse vises ofte som et ekstra symbol på tastene.
Extended_description-oc.utf-8: Amb d'unas disposicions de clavièrs, AltGr es una tòca de modificacion utilizada per entrar de caractèrs nombroses, principalament los qu'apartenon pas a la lenga que correspond a la disposicion del clavièr, coma los simbòls de las devisas estrangièras e las letras accentuadas. Aqueles caractèrs son generalament indicats jos forma de simbòls suplementaris sus las tòcas.
Extended_description-pa.utf-8: ਕਈ ਕੀ-ਬੋਰਡ ਲੇਆਉਟ ਵਿੱਚ AltGr ਇਕ ਬਦਲੀ ਹੋਈ ਸਵਿੱਚ ਹੁੰਦੀ ਹੈ ਜੋ ਨਾ-ਸੁਭਾਵਿਕ ਅੱਖਰ ਜੋ ਕਿ ਕੀ-ਬੋਰਡ ਲਈ ਆਮ ਨਹੀਂ ਹੁੰਦੇ, ਪਾਉਣ ਦੇ ਕੰਮ ਆਉਂਦੀ ਹੈ ਜਿਵੇਂ ਕਿ ਵਿਦੇਸ਼ੀ ਮੁਦਰਾ ਦਾ ਨਿਸ਼ਾਨ ਤੇ accented ਅੱਖਰ। ਇਹ ਆਮ ਤੋਰ ਤੇ ਵਾਧੂ ਨਿਸ਼ਾਨ ਬਣਾ ਕੇ ਸਵਿੱਚਾਂ ਤੇ ਉੱਕਰੀ ਹੁੰਦੀ ਹੈ ।
Extended_description-pl.utf-8: W niektórych układach klawiatur AltGr to klawisz modyfikujący, używany do wprowadzania niektórych znaków, zwłaszcza tych, które są niecodzienne w języku danego układu klawiatury, na przykład symbole zagranicznych walut lub akcentowanych liter. Są one często wydrukowane jako dodatkowy symbol na klawiszach.
Extended_description-pt.utf-8: Em alguns teclados, o AltGr serve de modificador para escrever alguns caracteres, especialmente alguns que são invulgares na língua configurada, tais como símbolos de moeda estrangeira e letras acentuadas. Estes símbolos são frequentemente indicados como símbolos extra nas teclas.
Extended_description-pt_br.utf-8: Com alguns layouts de teclado, AltGr é uma tecla modificadora usada para introduzir alguns caracteres, principalmente aqueles que não são usuais para o idioma do layout do teclado, como símbolos de moedas estrangeiras e letras acentuadas. Estes são frequentemente impressos como um símbolo extra sobre as teclas.
Extended_description-ro.utf-8: La anumite aranjamente de tastatură AltGr este o tastă de modificare, folosită pentru introducerea anumitor caractere, în special acelea care nu sunt uzuale pentru limba aranjamentului de tastatură, cum are fi simboluri pentru valute sau litere cu accent. Acestea sunt în multe cazuri inscripționate pe taste ca un simbol adițional.
Extended_description-ru.utf-8: В некоторых раскладках клавиатуры есть клавиша-модификатор AltGr, используемая для ввода, в основном, редко используемых в языке раскладки клавиатуры символов, например, символа национальной валюты и символы с диакритическим знаком. Они часто указаны на клавишах как дополнительные символы.
Extended_description-si.utf-8: ඇතැම් යතුරුපුවරු සැකසුම් වලදී, AltGr යතුර ඇතැම් අක්‍ෂර ඇතුලත් කිරීමට යොදාගන්නා විශේෂ යතුරකි. විදේශීය මූල්‍ය සංඛේත හා අක්‍ෂර වැනි යතුරුපුවරුවේ සාමාන්‍යෙන් නොපවතින යතුරු සඳහා ප්‍රධාන වශ්‍යෙන් යොදාගැනේ. මේවා බොහෝ විට අමතර අක්‍ෂර ලෙස යතුරු මත මුද්‍රණය කර ඇත.
Extended_description-sk.utf-8: V niektorých rozloženiach klávesnice je AltGr modifikátor používaný na zadávanie niektorých znakov, predovšetkým takých, ktoré sú v jazyku rozloženia klávesnice nezvyčajné. Tieto sú na klávesnici často vyznačené ako ďalšie symboly.
Extended_description-sl.utf-8: Pri nekaterih postavitvah tipkovnic je Desna izmenjalka tipka za spreminjaje. Uporablja se predvsem za vnos znakov, ki niso običajni za jezik postavitve tipkovnice. Taki znaki so lahko na primer znaki za valute ali naglašene črke. Pogosto so natisnjeni kot dodaten simbol na tipki.
Extended_description-sq.utf-8: Me disa formate tastierash, AltGr është një tast modifikues i përdorur për të futur disa karaktere ku primar janë ata që janë të vecantë për gjuhën e tastierëssi simbolet e një monedhe të huaj dhe shkronja të vjetra. Këto simbole zakonisht janë të printuara si një simbol shtesë në tast
Extended_description-sr.utf-8: Код неких распореда тастатуре, AltGr је тастер којим се могу откуцати додатни карактери, обично они који нису уобичајни за језик или распоред тастатуре, као на пример симболи валута и акцентована слова. Такави знаци су обично додатно означени на тастерима.
Extended_description-sr@latin.utf-8: Kod nekih rasporeda tastature, AltGr je taster kojim se mogu otkucati dodatni karakteri, obično oni koji nisu uobičajni za jezik ili raspored tastature, kao na primer simboli valuta i akcentovana slova. Takavi znaci su obično dodatno označeni na tasterima.
Extended_description-sv.utf-8: I en del tangentbordsupplägg så är AltGr en modifierande tangent som används för att skriva tecken som inte är vanliga i språket för tangentbordsupplägget. Exempelvis accenter eller symboler för utländsk valuta. Dessa finns vanligen utskrivna som extra tecken på tangenterna.
Extended_description-ta.utf-8: சில விசைப்பலகை இட அமைவுகளில் AltGr சில எழுத்துருக்களை உள்ளிட மாற்றி விசையாக அமைக்கப்படும். இந்த சில எழுத்துருக்கள் அந்தந்த மொழிக்கு சிறப்பானவை - வெளி நாட்டு பண குறிகள் சிறப்பு குறியிட்ட எழுத்துக்கள் போன்றவை. இவை பல சம்யங்களில் கூடுதல் சின்னங்களாக விசைகளில் காணப்படும்.
Extended_description-te.utf-8: కొన్ని కీబోర్డు లేఔట్లలో, AltGr ని కొన్ని అక్షరాలు(వాడుక భాషకి సంబంధించని విదేశ ద్రవ్య చిహ్నాలు మరియు ప్రత్యేక అక్షరాలు) ప్రవేశపెట్టటానికి వాడతారు. కీలపై వాటిని అదనపు చిహ్నలుగా ముద్రించివుంటాయి.
Extended_description-tg.utf-8: Баъзе тарҳбандиҳои ҳарфкалид тугмаи тағйирёбандаи AltGr барои вуруди баъзе аломатҳо истифода мешавад, асосан аломатҳое, ки барои забони тарҳбандии ҳарфкалид ғайриоддӣ мебошанд, монанди рамзҳои асъорӣ ва ҳарфҳои заданок. Бисёр мартаба ин аломатҳо ҳамчун иловагӣ дар тугмаҳои ҳарфкалид чоп карда мешаванд.
Extended_description-th.utf-8: ในผังแป้นพิมพ์บางแบบ AltGr จะใช้เป็นปุ่มประกอบในการป้อนอักขระบางตัว ซึ่งมักเป็นอักขระแปลกปลอมสำหรับภาษาของผังแป้นพิมพ์ เช่นสัญลักษณ์หน่วยเงินตราต่างประเทศ และอักขระที่มีเครื่องหมายกำกับเสียง อักขระเหล่านี้มักจะแสดงไว้เป็นอักขระพิเศษบนปุ่ม
Extended_description-tr.utf-8: Bazı klavye düzenlerinde AltGr çeşitli karakterlerin girilmesini sağlayan bir niteleyici tuştur.  Bu karakterlerin büyük bir bölümü, yabancı para simgeleri ve aksanlı harfler gibi, kullanılan klavye düzenine ait dilde yaygın olmayan karakterlerden oluşur. Eğer bir tuşta üçüncü bir simge görüyorsanız AltGr tuşu çoğunlukla bu simgenin girilmesini sağlamakta kullanılır.
Extended_description-ug.utf-8: بەزى ھەرپتاختا جايلاشتۇرۇشىدا، AltGr بەزى ھەرپلەرنى ئالماشتۇرۇپ كىرگۈزۈشكە ئىشلىتىلىدۇ، ئاساسلىقى نۆۋەتتىكى ھەرپتاختا جايلاشتۇرۇشىدا ئىنتايىن ئاز ئىشلىتىلىدىغان ھەرپلەرنى كىرگۈزۈشكە ئىشلىتىلىدۇ، مەسىلەن چەت تىللاردىكى پۇل بەلگىسى ۋە ئۇرغۇ بەلگىسى. بۇ ھەرپلەر ئادەتتە نورمىدىن ئارتۇق ھەرپلەر سۈپىتىدە ھەرپتاختىغا بېسىلغان بولىدۇ.
Extended_description-uk.utf-8: Для деяких розкладок клавіатури клавіша-модифікатор AltGr використовується для вводу деяких незвичних для мови розкладки клавіатури символів, таких як символи іноземних валют або акцентовані літери. Часто на клавішах роблять їх додаткові зображення.
Extended_description-vi.utf-8: Trên một số bố trí bàn phím nào đó, AltGr là một phím bổ trợ dùng để gõ một số ký tự, chính là ký tự khác với ngôn ngữ của bố trí bàn phím, v.d. ký hiệu tiền tệ nước ngoại và chữ có dấu phụ lạ. Ký tự như vậy thường được in trên phím dạng một ký hiệu bổ sung.
Extended_description-zh_cn.utf-8: 在一些键盘布局中，AltGr 是用来输入某些字符的修饰键，主要用来输入当前键盘布局的语言中很少使用到的字符，比如外国的货币符号和重音字母。这些字符通常会作为额外符号印在按键上。
Extended_description-zh_tw.utf-8: 在某些鍵盤的排列方式裡，會把 AltGr 當作修改鍵，用來輸入在該語言的鍵盤的排列方式裡一些不常用到的字元，像是別國的貨幣符號及重音字元之類的。這些鍵的上面常常會印有額外的符號。
Type: select

Name: keyboard-configuration/compose
Choices: No compose key, Right Alt (AltGr), Right Control, Right Logo key, Menu key, Left Logo key, Caps Lock
Choices-am.utf-8: የማዘጋጃ ቁልፍ አልተገኘም, ቀኝ Alt (AltGr), ቀኝ Control, ቀኝ Logo key, ምናሌ ቁልፍ, ግራ Logo key, Caps Lock
Choices-ar.utf-8: لا مفتاح تكوين, زر Alt اليمين (AltGr), زر Control الأيمن, مفتاح الشعار الأيمن, مفتاح القائمة, مفتاح الشعار الأيسر, Caps Lock
Choices-ast.utf-8: Ensin tecla Compose, Alt drecha (AltGr), Control Derecha, Tecla Logu Derecha, Tecla Menú, Tecla Logu Izquierda, Caps Lock
Choices-be.utf-8: Няма кнопкі compose, Правы Alt (AltGr), Правы Control, Правая кнопка Logo, Кнока меню, Левая кнопка Logo, Caps Lock
Choices-bg.utf-8: Без клавиш „Compose“, Десен Alt (AltGr), Десен Control, Десен клавиш с лого, Клавиш меню, Ляв клавиш с лого, Caps Lock
Choices-bn.utf-8: কোন কম্পোজ কী নয় , ডান Alt (AltGr), ডান কন্ট্রোল, ডান লোগো কী, মেনু কী, বাম লোগো কী, ক্যাপস্ লক
Choices-bo.utf-8: མཉམ་རྡེབ་མཐེབ་མེད་པ, Alt གཡས (AltGr), Control གཡོན, མཚོན་རྟགས་མཐེབ་གཡས, འདེམས་ཐོ་མཐེབ, མཚོན་རྟགས་མཐེབ་གཡོན, ཆེ་བྲིས་ཀྱི་ཟྭ
Choices-bs.utf-8: Bez compose tipke, Desni Alt (AltGr), Desni Control taster, Desni Logo taster, Meni taster, Lijevi Logo taster, Caps Lock
Choices-ca.utf-8: Sense tecla de composició, Alt dret (AltGr), Control dret, Tecla de logotip dreta, Tecla de menú dreta, Tecla de logotip esquerra, Fixació de majúscules
Choices-cs.utf-8: Bez klávesy Compose, Pravý Alt (AltGr), Pravý Control, Pravá klávesa logo, Klávesa Menu, Levá klávesa logo, Caps Lock
Choices-cy.utf-8: Dim bysell cyfansoddi, Alt Dde (AltGr), Control Dde, Bysell Logo Dde, Bysell bwydlen, Bysell Logo Chwith, Capiau Clo
Choices-da.utf-8: Ingen Compose-tast, Højre Alt (AltGr), Højre Control, Højre Logo-tast, Menu-tast, Venstre Logo-tast, Caps Lock
Choices-de.utf-8: Keine Compose-Taste, Alt rechts (AltGr), Strg rechts, Windows-Taste rechts, Menütaste, Windows-Taste links, Feststelltaste
Choices-dz.utf-8: ཀོམ་པོསི་ལྡེ་ཡིག་མིན་འདུག, གཡས་ཀྱི་གདམ་ལྡེ་ (AltGr), གཡས་ཀྱི་ཚད་འཛིན།, གཡས་ཀྱི་ལས་རྟགས་ལྡེ་ཡིག, དཀར་ཆག་ལྡེ་ཡིག, གཡོན་གྱི་ལས་རྟགས་ལྡེ་ཡིག, ཚུགས་ལྡེ།
Choices-el.utf-8: Μη διαθέσιμο πλήκτρο σύνθεσης (Compose), Δεξί Alt (AltGr), Right Control, Πλήκτρο Right Logo, Πλήκτρο Menu, Πλήκτρο Left Logo, Caps Lock
Choices-eo.utf-8: Neniu kombino-klavo, Dekstra Alt (AltGr), Dekstra Control, Dekstra Emblemo-klavo, Menu-klavo, Maldekstra Emblemo-klavo, Majuskla Baskulo
Choices-es.utf-8: Sin tecla modificadora, Alt derecho (AltGr), Control derecho, Tecla derecha de logo, Tecla de menú, Tecla izquierda de logo, Bloqueo de mayúsculas
Choices-et.utf-8: Koosteklahvi pole, Parem Alt (AltGr), Parem Control, Parem logoklahv, Menüüklahv, Vasak logoklahv, Caps Lock
Choices-eu.utf-8: Tekla konposaturik ez, Eskuineko Alt (AltGr), Eskuineko Ktrl, Eskuineko Logotipoa tekla, Menua tekla, Ezkerreko Logotipoa tekla, Blok Maius
Choices-fa.utf-8: کلیدهای غیر ساختگی, دگرساز راست, مهار راست, سوپر راست, کلید فهرست, سوپر چپ, قفل تبدیل
Choices-fi.utf-8: Ei yhdistelmänäppäintä, Oikea Alt (AltGr), Oikea Control, Oikea Logo-näppäin, Menu-näppäin, Vasen Logo-näppäin, Caps Lock
Choices-fr.utf-8: Pas de touche « compose », Touche Alt de droite (AltGr), Touche Ctrl de droite, Touche « logo » de droite, Touche Menu, Touche « logo » de gauche, Verrouillage Majuscule
Choices-ga.utf-8: Gan eochair athraithe, Alt Ar Dheis (AltGr), Ctrl Ar Dheis, Eochair lógó ar dheis, Eochair roghchláir, Eochair lógó ar chlé, Glas Ceannlitreacha
Choices-gl.utf-8: Non hai tecla Compose, Tecla Alt dereita (Alt Gr), Tecla Ctrl dereita, Tecla Logo dereita, Tecla Menú, Tecla Logo esquerda, Bloq maiús
Choices-gu.utf-8: કોઇ કોમ્પોઝ કળ નહીં, જમણી અલ્ટ (AltGr), જમણી કંટ્રોલ, જમણી લોગો કળ, મેનુ કળ, ડાબી લોગો કળ, કેપ્સ-લૉક
Choices-he.utf-8: אין מקש compose, Alt ימני (AltGr), Control ימני, מקש לוגו ימני, מקש תפריט, מקש לוגו שמאלי, Caps Lock
Choices-hi.utf-8: कोई रचना नहीं कुंजी, दाहिना ऑल्ट (AltGr), दाहिना कन्ट्रोल, दाहिनी चिह्न कुंजी, मेनु कुंजी, बाहिनी चित्र कुंजी, कैप्स लॉक
Choices-hr.utf-8: Nema tipke sastavljanja, Desni Alt (AltGr), Desna Control tipka, Desna Logo tipka, Tipka Izbornika, Lijeva Logo tipka, Caps Lock
Choices-hu.utf-8: Nincs kombinációs billentyű, Jobb Alt (AltGr), Jobb Control, Jobb logó billentyű, Menü billentyű, Bal logó billentyű, Caps Lock
Choices-id.utf-8: Tanpa tombol kombinasi, Alt (AltGr) kanan, Ctrl Kanan, Tombol Logo Kanan, Tombol Menu, Tombol Logo Kiri, Caps Lock
Choices-is.utf-8: Enginn samsetningarlykill (compose key), Hægri Alt lykill (AltGr), Vinstri Ctrl, Hægri Merkja-lykill (Win), Menu-lykill, Vinstri Merkja-lykill (Win), Caps Lock
Choices-it.utf-8: Nessun tasto «componi», Alt destro (AltGr), Ctrl destro, Tasto Windows destro, Tasto menù, Tasto Windows sinistro, Bloc Maiusc
Choices-ja.utf-8: コンポーズキーなし, 右 Alt (AltGr), 右 Control, 右ロゴキー, メニューキー, 左ロゴキー, Caps Lock
Choices-kab.utf-8: Ulac taqeffalt n tira, Alt ayeffus (AltGr), Control ayeffus, Tasarut n ulugu tayeffust, Tasarut n wumuɣ, Tasarut n ulugu tazelmaḍt, Asekkeṛ n yisekkilen imeqqranen
Choices-kk.utf-8: Compose пернесі жоқ, Оң жақ Alt (AltGr), Оң жақ Control, Оң жақ Logo пернесі, Menu пернесі, Сол жақ Logo пернесі, Caps Lock
Choices-km.utf-8: គ្មាន​គ្រាប់ចុច​តែង​ទេ, Alt (AltGr) ខាង​ស្ដាំ, គ្រាប់ចុច​បញ្ជា (Ctrl) ខាង​ស្ដាំ, គ្រាប់ចុច Logo ខាង​ស្ដាំ, គ្រាប់ចុច​ម៉ឺនុយ, គ្រាប់ Logo ខាង​ឆ្វេង, ប្ដូរ​ជាប់ (Caps Lock)
Choices-kn.utf-8: ಕಂಪೋಸ್ ಕೀಲಿ ಇರುವುದಿಲ್ಲ, ಬಲ ಆಲ್ಟ್ (AltGr), ಬಲ ಕಂಟ್ರೋಲ್, ಬಲ ಲೋಗೊ ಕೀಲಿ, ಮೆನು ಕೀಲಿ, ಎಡ ಲೋಗೊ ಕೀಲಿ, ಕ್ಯಾಪ್ಸ್ ಲಾಕ್
Choices-ko.utf-8: Compose 키 없음, 오른쪽 Alt (AltGr), 오른쪽 Control, 오른쪽 로고 키, 메뉴 키, 왼쪽 로고 키, Caps Lock
Choices-ku.utf-8: Bişkoka compose tuneye, Rast Alt (AlrGr), control a rastê, Bişkoka logo ya rastê, Mifteya Pêşekê, Bişkoka logo ya çepê, Caps Lock
Choices-lo.utf-8: ບໍ່ມີການປະກອບເປັນສຳຄັນ, Alt ຂວາ (AltGr), ຄວບຄຸມຂວາ, ແປ້ນໂລໂກ້ຂວາ, ເມນູສຳຄັນ, ແປ້ນໂລໂກ້ຊ້າຍ, Caps Lock
Choices-lt.utf-8: Komponavimo klavišo nenaudoti, Dešinysis Alt (Lyg3), Dešinysis Vald, Dešinysis Logo klavišas, Meniu klavišas, Kairysis Logo klavišas, Didžiosios raidės
Choices-lv.utf-8: Bez compose taustiņa, Labais Alt (AltGr), Labais Ctrl, Labais Logo taustiņš, Izvēlnes taustiņš, Kreisais Logo taustiņš, Caps Lock
Choices-mk.utf-8: Без копче за комбинирање, Десен Alt (AltGr), Десен Control, Десното Лого копче, Мени копче, Левото лого копче, Caps Lock
Choices-ml.utf-8: കമ്പോസ് കീ ഇല്ല, വലത് ആള്‍ട്ട് (AltGr), വലത് കണ്ട്രോള്‍, വലത് ലോഗോ കീ, മെനു കീ, ഇടത് ലോഗോ കീ, കാപ്സ് ലോക്ക്
Choices-mr.utf-8: काँपोझ कळ नाही, उजवी Alt (AltGr), उजवी Control, उजवी लोगो कळ, मेनू कळ, डावी लोगो कळ, Caps Lock
Choices-nb.utf-8: Ingen Compose-tast, Høyre Alt (AltGr), Høyre Ctrl, Høyre logotast, Menytast, Venstre logotast, Caps Lock
Choices-nl.utf-8: Geen samenstellingstoets, Alt-Rechts (AltGr), Control-Rechts, Logotoets-Rechts, Menutoets, Logotoets-Links, Caps Lock
Choices-nn.utf-8: Ingen modifiseringstast, Høgre Alt (AltGr), Høgre Ctrl, Høgre logotast, Menytast, Venstre logotast, Caps Lock
Choices-no.utf-8: Ingen Compose-tast, Høyre Alt (AltGr), Høyre Ctrl, Høyre logotast, Menytast, Venstre logotast, Caps Lock
Choices-oc.utf-8: Pas de tòca « compose », Tòca Alt de drecha (AltGr), Ctrl drecha, Tòca « lògo » de drecha, Tòca menú, Tòca « lògo » d'esquèrra, Verrolhatge numeric
Choices-pa.utf-8: ਕੋਈ ਸੰਰਚਨਾ ਸਵਿੱਚ ਨਹੀਂ, ਸੱਜਾ Alt (AltGr), ਸੱਜਾ ਕੰਟਰੋਲ, ਸੱਜੀ ਲੋਗੋ ਸਵਿੱਚ, ਮੇਨੂ ਸਵਿੱਚ, ਖੱਬੀ ਲੋਗੋ ਸਵਿੱਚ, ਕੈਪਸ ਲਾਕ
Choices-pl.utf-8: Bez klawisza Compose, Prawy Alt (AltGr), Prawy Control, Prawy klawisz logo, Klawisz menu, Lewy klawisz logo, Caps Lock
Choices-pt.utf-8: Sem tecla compose, Alt direito (AltGr), Control Direito, Tecla Logotipo Direito, Tecla Menu, Tecla de Logotipo Esquerdo, Caps Lock
Choices-pt_br.utf-8: Sem tecla Compose, Alt Direito (AltGr), Control Direito, Tecla Logo Direita, Tecla Menu, Tecla Logo Esquerda, Caps Lock
Choices-ro.utf-8: Fără tastă de compunere, Alt dreapta (AltGr), Control dreapta, Tasta logo dreapta, Tasta meniu, Tasta logo stânga, Caps Lock
Choices-ru.utf-8: нет составной клавиши, правый Alt (AltGr), правый Control, правая клавиша с логотипом, клавиша с меню, левая клавиша с логотипом, Caps Lock
Choices-si.utf-8: සම්පාදන යතුරක් නැත, දකුණු Alt (AltGr), දකුණු Control, දකුණු ලාංඡය යතුර, මෙනු යතුර, වම් ලාංඡන යතුර, කැප්ස් යතුර
Choices-sk.utf-8: Žiaden kombinačný kláves, Pravý Alt (AltGr), Pravý Control, Pravý kláves Logo, Kláves Menu, Ľavý kláves Logo, Caps Lock
Choices-sl.utf-8: Brez tipke za sestavljanje, Desna izmenjalka (AltGR), Desna krmilka (Control), Desna tipka z znakom, Menijska tipka, Leva tipka z znakom, Caps Lock
Choices-sq.utf-8: Mungon çelësi Compose, Alt e djathtë (AltGr), Kontroll i Djathtë, Logo key i djathtë, Çelësi i menysë, Logo key i Majtë, Caps Lock
Choices-sr.utf-8: Без compose тастера, Десни Alt (AltGr), Десни Control, Десни лого тастер, Мени тастер, Леви лого тастер, Caps Lock
Choices-sr@latin.utf-8: Bez compose tastera, Desni Alt (AltGr), Desni Control, Desni logo taster, Meni taster, Levi logo taster, Caps Lock
Choices-sv.utf-8: Ingen komposittangent, Alt\, höger (AltGr), Control\, höger, Tangent med logotyp\, höger, Menyknapp, Tangent med logotyp\, vänster, Caps Lock
Choices-ta.utf-8: உருவாக்க விசை இல்லை, வலது ஆல்ட் (AltGr), வலது கன்ட்ரோல், வலது லோகோ விசை, மெனு விசை, இடது லோகோ விசை, கேப்ஸ் பூட்டு
Choices-te.utf-8: కంపోస్ కీ లేదు, కుడి ఆల్ట్ (AltGr), కుడి కంట్రోల్, కుడి బొమ్మ కీ, మెనూ కీ, ఎడమ బొమ్మ కీ, కేప్స్ లాక్
Choices-tg.utf-8: Бе тугмаи эҷодкунӣ, Alt-и рост (AltGr), Control-и рост, Тугмаи рости тамға, Тугмаи меню, Тугмаи чапи тамға, Caps Lock
Choices-th.utf-8: ไม่ใช้ปุ่มผสมอักขระ, Alt ขวา (AltGr), Control ขวา, ปุ่มโลโก้ขวา, ปุ่มเมนู, ปุ่มโลโก้ซ้าย, Caps Lock
Choices-tr.utf-8: Birleştirme (Compose) tuşu yok, Sağ Alt (AltGr), Sağ Control, Sağ Logo tuşu, Menü tuşu, Sol Logo tuşu, Caps Lock (Büyük Harf Kilidi)
Choices-ug.utf-8: بىرىكمە كۇنۇپكا يوق, ئوڭ Alt (AltGr), ئوڭ Control, ئوڭ  Logo كۇنۇپكا, تىزىملىك كۇنۇپكا, سول Logo كۇنۇپكا, CapsLock
Choices-uk.utf-8: Без клавіші Compose, Правий Alt (AltGr), Правий Control, Права клавіша Logo, Клавіша Menu, Ліва клавіша Logo, Caps Lock
Choices-vi.utf-8: Không có phím cấu tạo, Alt phải (AltGr), Ctrl phải, Phím Win phải, Phím trình đơn, Phím Win trái, Caps Lock
Choices-zh_cn.utf-8: 无组合键, 右 Alt 键 (AltGr), 右 Control 键, 右徽标键, 菜单键, 左徽标键, 大写锁定键
Choices-zh_tw.utf-8: 沒有 Compose 鍵, 左 Alt (AltGr), 右 Control, 右 Logo 鍵, Menu 鍵, 左 Logo 鍵, Caps Lock
Default: No compose key
Description: Compose key:
Description-ar.utf-8: مفتاح التكوين:
Description-ast.utf-8: Tecla Compose:
Description-be.utf-8: Кнопка Compose:
Description-bg.utf-8: Клавиш „Compose“:
Description-bn.utf-8: কম্পোজ কী
Description-bo.utf-8: མཉམ་རྡེབ་མཐེབ：
Description-bs.utf-8: Compose tipka:
Description-ca.utf-8: Tecla de composició:
Description-cs.utf-8: Klávesa Compose:
Description-cy.utf-8: Y bysell Cyfansoddi:
Description-da.utf-8: Compose-tast:
Description-de.utf-8: Compose-Taste:
Description-dz.utf-8: ལྡེ་ཡིག་བཟོ:
Description-el.utf-8: Πλήκτρο Compose:
Description-eo.utf-8: Kombino-klavo:
Description-es.utf-8: Tecla modificadora:
Description-et.utf-8: Koosteklahv:
Description-eu.utf-8: Tekla konposatua:
Description-fa.utf-8: کلید های ساختگی:
Description-fi.utf-8: Yhdistelmänäppäin:
Description-fr.utf-8: Touche « compose » :
Description-ga.utf-8: Eochair athraithe:
Description-gl.utf-8: Tecla Compose:
Description-gu.utf-8: કોમ્પોઝ કળ:
Description-he.utf-8: מקש compose:
Description-hi.utf-8: कम्पोज़ कुंजी:
Description-hr.utf-8: Tipka sastavljanja:
Description-hu.utf-8: Kombinációs billentyű:
Description-id.utf-8: Tombol Kombinasi:
Description-is.utf-8: Samsetningarlykill:
Description-it.utf-8: Tasto «componi»:
Description-ja.utf-8: コンポーズキー:
Description-kab.utf-8: Taqeffalt n tira:
Description-kk.utf-8: Compose пернесі:
Description-km.utf-8: គ្រាប់ចុច​តែង ៖
Description-kn.utf-8: ಕಂಪೋಸ್ ಕೀಲಿ :
Description-ko.utf-8: Compose 키:
Description-ku.utf-8: Bişkoka compose:
Description-lo.utf-8: ຂຽນສຳຄັນ
Description-lt.utf-8: Komponavimo klavišas:
Description-lv.utf-8: Compose taustiņš:
Description-mk.utf-8: Копче за комбинирање:
Description-ml.utf-8: കമ്പോസ് കീ:
Description-mr.utf-8: काँपोझ कळ:
Description-nb.utf-8: Compose-tast:
Description-nl.utf-8: Samenstellingstoets:
Description-nn.utf-8: Modifiseringstast:
Description-no.utf-8: Compose-tast:
Description-oc.utf-8: Tòca « compose » :
Description-pa.utf-8: ਸੰਰਚਨਾ ਸਵਿੱਚ:
Description-pl.utf-8: Klawisz Compose:
Description-pt.utf-8: Tecla compose:
Description-pt_br.utf-8: Tecla Compose:
Description-ro.utf-8: Tasta de compunere:
Description-ru.utf-8: Составная клавиша:
Description-si.utf-8: සම්පාදන යතුර:
Description-sk.utf-8: Kombinačný kláves:
Description-sl.utf-8: Tipka za sestavljanje:
Description-sq.utf-8: Çelësi Compose:
Description-sr.utf-8: Compose тастер:
Description-sr@latin.utf-8: Compose taster:
Description-sv.utf-8: Komposittangent:
Description-ta.utf-8: உருவாக்க விசை:
Description-te.utf-8: కంపోస్ కీ:
Description-tg.utf-8: Тугмаи эҷодкунӣ:
Description-th.utf-8: ปุ่มผสมอักขระ (Compose key):
Description-tr.utf-8: Birleştirme (Compose) tuşu:
Description-ug.utf-8: بىرىكمە كۇنۇپكا:
Description-uk.utf-8: Клавіша Compose:
Description-vi.utf-8: Phím cấu tạo :
Description-zh_cn.utf-8: 组合键：
Description-zh_tw.utf-8: Compose 鍵:
Extended_description: The Compose key (known also as Multi_key) causes the computer to interpret the next few keystrokes as a combination in order to produce a character not found on the keyboard.\n\nOn the text console the Compose key does not work in Unicode mode. If not in Unicode mode, regardless of what you choose here, you can always also use the Control+period combination as a Compose key.
Extended_description-ar.utf-8: مفتاح التكوين (والمعروف أيضاً بمفتاح التعدد Multi_key) يجعل الحاسب يعتبرضربات المفاتيح التالية كمجموعة لإنتاج حرف غير موجود في لوحة المفاتيح.\n\nفي الطرفية النصيّة لا يعمل مفتاح التكوين في وضع يونيكود. وإن لم تكن في وضع يونيكود، فبغض النظر عما ستختار هنا، يمكنك دائماً استخدام زر Control+نقطة كمفتاح تكوين.
Extended_description-ast.utf-8: La tecla Compose (tamién conocida como Multi_key) fai que l'ordenador interprete les prósimes pulsaciones de tecla como una combinación, cola fin de producir un caráuter que nun s'alcuentra nel tecláu.\n\nNa consola de testu la tecla Componer nun trabaya nel mou Unicode. Si non ye mou Unicode, independientemente de lo que escueyas equí, siempre pues también usar la combinación Control + períodu como tecla Compon# $Id$
package ExtUtils::MakeMaker;

use strict;
use warnings;

BEGIN {require 5.006;}

require Exporter;
use ExtUtils::MakeMaker::Config;
use ExtUtils::MakeMaker::version; # ensure we always have our fake version.pm
use Carp;
use File::Path;
my $CAN_DECODE = eval { require ExtUtils::MakeMaker::Locale; }; # 2 birds, 1 stone
eval { ExtUtils::MakeMaker::Locale::reinit('UTF-8') }
  if $CAN_DECODE and Encode::find_encoding('locale')->name eq 'ascii';

our $Verbose = 0;       # exported
our @Parent;            # needs to be localized
our @Get_from_Config;   # referenced by MM_Unix
our @MM_Sections;
our @Overridable;
my @Prepend_parent;
my %Recognized_Att_Keys;
our %macro_fsentity; # whether a macro is a filesystem name
our %macro_dep; # whether a macro is a dependency

our $VERSION = '7.64';
$VERSION =~ tr/_//d;

# Emulate something resembling CVS $Revision$
(our $Revision = $VERSION) =~ s{_}{};
$Revision = int $Revision * 10000;

our $Filename = __FILE__;   # referenced outside MakeMaker

our @ISA = qw(Exporter);
our @EXPORT    = qw(&WriteMakefile $Verbose &prompt &os_unsupported);
our @EXPORT_OK = qw($VERSION &neatvalue &mkbootstrap &mksymlists
                    &WriteEmptyMakefile &open_for_writing &write_file_via_tmp
                    &_sprintf562);

# These will go away once the last of the Win32 & VMS specific code is
# purged.
my $Is_VMS     = $^O eq 'VMS';
my $Is_Win32   = $^O eq 'MSWin32';
our $UNDER_CORE = $ENV{PERL_CORE}; # needs to be our

full_setup();

require ExtUtils::MM;  # Things like CPAN assume loading ExtUtils::MakeMaker
                       # will give them MM.

require ExtUtils::MY;  # XXX pre-5.8 versions of ExtUtils::Embed expect
                       # loading ExtUtils::MakeMaker will give them MY.
                       # This will go when Embed is its own CPAN module.


# 5.6.2 can't do sprintf "%1$s" - this can only do %s
sub _sprintf562 {
    my ($format, @args) = @_;
    for (my $i = 1; $i <= @args; $i++) {
        $format =~ s#%$i\$s#$args[$i-1]#g;
    }
    $format;
}

sub WriteMakefile {
    croak "WriteMakefile: Need even number of args" if @_ % 2;

    require ExtUtils::MY;
    my %att = @_;

    _convert_compat_attrs(\%att);

    _verify_att(\%att);

    my $mm = MM->new(\%att);
    $mm->flush;

    return $mm;
}


# Basic signatures of the attributes WriteMakefile takes.  Each is the
# reference type.  Empty value indicate it takes a non-reference
# scalar.
my %Att_Sigs;
my %Special_Sigs = (
 AUTHOR             => 'ARRAY',
 C                  => 'ARRAY',
 CONFIG             => 'ARRAY',
 CONFIGURE          => 'CODE',
 DIR                => 'ARRAY',
 DL_FUNCS           => 'HASH',
 DL_VARS            => 'ARRAY',
 EXCLUDE_EXT        => 'ARRAY',
 EXE_FILES          => 'ARRAY',
 FUNCLIST           => 'ARRAY',
 H                  => 'ARRAY',
 IMPORTS            => 'HASH',
 INCLUDE_EXT        => 'ARRAY',
 LIBS               => ['ARRAY',''],
 MAN1PODS           => 'HASH',
 MAN3PODS           => 'HASH',
 META_ADD           => 'HASH',
 META_MERGE         => 'HASH',
 OBJECT             => ['ARRAY', ''],
 PL_FILES           => 'HASH',
 PM                 => 'HASH',
 PMLIBDIRS          => 'ARRAY',
 PMLIBPARENTDIRS    => 'ARRAY',
 PREREQ_PM          => 'HASH',
 BUILD_REQUIRES     => 'HASH',
 CONFIGURE_REQUIRES => 'HASH',
 TEST_REQUIRES      => 'HASH',
 SKIP               => 'ARRAY',
 TYPEMAPS           => 'ARRAY',
 XS                 => 'HASH',
 XSBUILD            => 'HASH',
 VERSION            => ['version',''],
 _KEEP_AFTER_FLUSH  => '',

 clean      => 'HASH',
 depend     => 'HASH',
 dist       => 'HASH',
 dynamic_lib=> 'HASH',
 linkext    => 'HASH',
 macro      => 'HASH',
 postamble  => 'HASH',
 realclean  => 'HASH',
 test       => 'HASH',
 tool_autosplit => 'HASH',
);

@Att_Sigs{keys %Recognized_Att_Keys} = ('') x keys %Recognized_Att_Keys;
@Att_Sigs{keys %Special_Sigs} = values %Special_Sigs;

sub _convert_compat_attrs { #result of running several times should be same
    my($att) = @_;
    if (exists $att->{AUTHOR}) {
        if ($att->{AUTHOR}) {
            if (!ref($att->{AUTHOR})) {
                my $t = $att->{AUTHOR};
                $att->{AUTHOR} = [$t];
            }
        } else {
                $att->{AUTHOR} = [];
        }
    }
}

sub _verify_att {
    my($att) = @_;

    foreach my $key (sort keys %$att) {
        my $val = $att->{$key};
        my $sig = $Att_Sigs{$key};
        unless( defined $sig ) {
            warn "WARNING: $key is not a known parameter.\n";
            next;
        }

        my @sigs   = ref $sig ? @$sig : $sig;
        my $given  = ref $val;
        unless( grep { _is_of_type($val, $_) } @sigs ) {
            my $takes = join " or ", map { _format_att($_) } @sigs;

            my $has = _format_att($given);
            warn "WARNING: $key takes a $takes not a $has.\n".
                 "         Please inform the author.\n";
        }
    }
}


# Check if a given thing is a reference or instance of $type
sub _is_of_type {
    my($thing, $type) = @_;

    return 1 if ref $thing eq $type;

    local $SIG{__DIE__};
    return 1 if eval{ $thing->isa($type) };

    return 0;
}


sub _format_att {
    my $given = shift;

    return $given eq ''        ? "string/number"
         : uc $given eq $given ? "$given reference"
         :                       "$given object"
         ;
}


sub prompt ($;$) {  ## no critic
    my($mess, $def) = @_;
    confess("prompt function called without an argument")
        unless defined $mess;

    my $isa_tty = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ;

    my $dispdef = defined $def ? "[$def] " : " ";
    $def = defined $def ? $def : "";

    local $|=1;
    local $\;
    print "$mess $dispdef";

    my $ans;
    if ($ENV{PERL_MM_USE_DEFAULT} || (!$isa_tty && eof STDIN)) {
        print "$def\n";
    }
    else {
        $ans = <STDIN>;
        if( defined $ans ) {
            $ans =~ s{\015?\012$}{};
        }
        else { # user hit ctrl-D
            print "\n";
        }
    }

    return (!defined $ans || $ans eq '') ? $def : $ans;
}

sub os_unsupported {
    die "OS unsupported\n";
}

sub eval_in_subdirs {
    my($self) = @_;
    use Cwd qw(cwd abs_path);
    my $pwd = cwd() || die "Can't figure out your cwd!";

    local @INC = map eval {abs_path($_) if -e} || $_, @INC;
    push @INC, '.';     # '.' has to always be at the end of @INC

    foreach my $dir (@{$self->{DIR}}){
        my($abs) = $self->catdir($pwd,$dir);
        eval { $self->eval_in_x($abs); };
        last if $@;
    }
    chdir $pwd;
    die $@ if $@;
}

sub eval_in_x {
    my($self,$dir) = @_;
    chdir $dir or carp("Couldn't change to directory $dir: $!");

    {
        package main;
        do './Makefile.PL';
    };
    if ($@) {
#         if ($@ =~ /prerequisites/) {
#             die "MakeMaker WARNING: $@";
#         } else {
#             warn "WARNING from evaluation of $dir/Makefile.PL: $@";
#         }
        die "ERROR from evaluation of $dir/Makefile.PL: $@";
    }
}


# package name for the classes into which the first object will be blessed
my $PACKNAME = 'PACK000';

sub full_setup {
    $Verbose ||= 0;

    my @dep_macros = qw/
    PERL_INCDEP        PERL_ARCHLIBDEP     PERL_ARCHIVEDEP
    /;

    my @fs_macros = qw/
    FULLPERL XSUBPPDIR

    INST_ARCHLIB INST_SCRIPT INST_BIN INST_LIB INST_MAN1DIR INST_MAN3DIR
    INSTALLDIRS
    DESTDIR PREFIX INSTALL_BASE
    PERLPREFIX      SITEPREFIX      VENDORPREFIX
    INSTALLPRIVLIB  INSTALLSITELIB  INSTALLVENDORLIB
    INSTALLARCHLIB  INSTALLSITEARCH INSTALLVENDORARCH
    INSTALLBIN      INSTALLSITEBIN  INSTALLVENDORBIN
    INSTALLMAN1DIR          INSTALLMAN3DIR
    INSTALLSITEMAN1DIR      INSTALLSITEMAN3DIR
    INSTALLVENDORMAN1DIR    INSTALLVENDORMAN3DIR
    INSTALLSCRIPT   INSTALLSITESCRIPT  INSTALLVENDORSCRIPT
    PERL_LIB        PERL_ARCHLIB
    SITELIBEXP      SITEARCHEXP

    MAKE LIBPERL_A LIB PERL_SRC PERL_INC
    PPM_INSTALL_EXEC PPM_UNINSTALL_EXEC
    PPM_INSTALL_SCRIPT PPM_UNINSTALL_SCRIPT
    /;

    my @attrib_help = qw/

    AUTHOR ABSTRACT ABSTRACT_FROM BINARY_LOCATION
    C CAPI CCFLAGS CONFIG CONFIGURE DEFINE DIR DISTNAME DISTVNAME
    DL_FUNCS DL_VARS
    EXCLUDE_EXT EXE_FILES FIRST_MAKEFILE
    FULLPERLRUN FULLPERLRUNINST
    FUNCLIST H IMPORTS

    INC INCLUDE_EXT LDFROM LIBS LICENSE
    LINKTYPE MAKEAPERL MAKEFILE MAKEFILE_OLD MAN1PODS MAN3PODS MAP_TARGET
    META_ADD META_MERGE MIN_PERL_VERSION BUILD_REQUIRES CONFIGURE_REQUIRES
    MYEXTLIB NAME NEEDS_LINKING NOECHO NO_META NO_MYMETA NO_PACKLIST NO_PERLLOCAL
    NORECURS NO_VC OBJECT OPTIMIZE PERL_MALLOC_OK PERL PERLMAINCC PERLRUN
    PERLRUNINST PERL_CORE
    PERM_DIR PERM_RW PERM_RWX MAGICXS
    PL_FILES PM PM_FILTER PMLIBDIRS PMLIBPARENTDIRS POLLUTE
    PREREQ_FATAL PREREQ_PM PREREQ_PRINT PRINT_PREREQ PUREPERL_ONLY
    SIGN SKIP TEST_REQUIRES TYPEMAPS UNINST VERSION VERSION_FROM XS
    XSBUILD XSMULTI XSOPT XSPROTOARG XS_VERSION
    clean depend dist dynamic_lib linkext macro realclean tool_autosplit

    MAN1EXT MAN3EXT

    MACPERL_SRC MACPERL_LIB MACLIBS_68K MACLIBS_PPC MACLIBS_SC MACLIBS_MRC
    MACLIBS_ALL_68K MACLIBS_ALL_PPC MACLIBS_SHARED
        /;
    push @attrib_help, @fs_macros;
    @macro_fsentity{@fs_macros, @dep_macros} = (1) x (@fs_macros+@dep_macros);
    @macro_dep{@dep_macros} = (1) x @dep_macros;

    # IMPORTS is used under OS/2 and Win32

    # @Overridable is close to @MM_Sections but not identical.  The
    # order is important. Many subroutines declare macros. These
    # depend on each other. Let's try to collect the macros up front,
    # then pasthru, then the rules.

    # MM_Sections are the sections we have to call explicitly
    # in Overridable we have subroutines that are used indirectly


    @MM_Sections =
        qw(

 post_initialize const_config constants platform_constants
 tool_autosplit tool_xsubpp tools_other

 makemakerdflt

 dist macro depend cflags const_loadlibs const_cccmd
 post_constants

 pasthru

 special_targets
 c_o xs_c xs_o
 top_targets blibdirs linkext dlsyms dynamic_bs dynamic
 dynamic_lib static static_lib manifypods processPL
 installbin subdirs
 clean_subdirs clean realclean_subdirs realclean
 metafile signature
 dist_basics dist_core distdir dist_test dist_ci distmeta distsignature
 install force perldepend makefile staticmake test ppd

          ); # loses section ordering

    @Overridable = @MM_Sections;
    push @Overridable, qw[

 libscan makeaperl needs_linking
 subdir_x test_via_harness test_via_script

 init_VERSION init_dist init_INST init_INSTALL init_DEST init_dirscan
 init_PM init_MANPODS init_xs init_PERL init_DIRFILESEP init_linker
                         ];

    push @MM_Sections, qw[

 pm_to_blib selfdocument

                         ];

    # Postamble needs to be the last that was always the case
    push @MM_Sections, "postamble";
    push @Overridable, "postamble";

    # All sections are valid keys.
    @Recognized_Att_Keys{@MM_Sections} = (1) x @MM_Sections;

    # we will use all these variables in the Makefile
    @Get_from_Config =
        qw(
           ar cc cccdlflags ccdlflags cpprun dlext dlsrc exe_ext full_ar ld
           lddlflags ldflags libc lib_ext obj_ext osname osvers ranlib
           sitelibexp sitearchexp so
          );

    # 5.5.3 doesn't have any concept of vendor libs
    push @Get_from_Config, qw( vendorarchexp vendorlibexp ) if "$]" >= 5.006;

    foreach my $item (@attrib_help){
        $Recognized_Att_Keys{$item} = 1;
    }
    foreach my $item (@Get_from_Config) {
        $Recognized_Att_Keys{uc $item} = $Config{$item};
        print "Attribute '\U$item\E' => '$Config{$item}'\n"
            if ($Verbose >= 2);
    }

    #
    # When we eval a Makefile.PL in a subdirectory, that one will ask
    # us (the parent) for the values and will prepend "..", so that
    # all files to be installed end up below OUR ./blib
    #
    @Prepend_parent = qw(
           INST_BIN INST_LIB INST_ARCHLIB INST_SCRIPT
           MAP_TARGET INST_MAN1DIR INST_MAN3DIR PERL_SRC
           PERL FULLPERL
    );
}

sub _has_cpan_meta_requirements {
    return eval {
      require CPAN::Meta::Requirements;
      CPAN::Meta::Requirements->VERSION(2.130);
      # Make sure vstrings can be handled. Some versions of CMR require B to
      # do this, which won't be available in miniperl.
      CPAN::Meta::Requirements->new->add_string_requirement('Module' => v1.2);
      1;
    };
}

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

    _convert_compat_attrs($self) if defined $self && $self;

    # Store the original args passed to WriteMakefile()
    foreach my $k (keys %$self) {
        $self->{ARGS}{$k} = $self->{$k};
    }

    $self = {} unless defined $self;

    # Temporarily bless it into MM so it can be used as an
    # object.  It will be blessed into a temp package later.
    bless $self, "MM";

    # Cleanup all the module requirement bits
    my %key2cmr;
    for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
        $self->{$key}      ||= {};
        if (_has_cpan_meta_requirements) {
            my $cmr = CPAN::Meta::Requirements->from_string_hash(
                $self->{$key},
                {
                  bad_version_hook => sub {
                    #no warnings 'numeric'; # module doesn't use warnings
                    my $fallback;
                    if ( $_[0] =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
                      $fallback = sprintf "%f", $_[0];
                    } else {
                      ($fallback) = $_[0] ? ($_[0] =~ /^([0-9.]+)/) : 0;
                      $fallback += 0;
                      carp "Unparsable version '$_[0]' for prerequisite $_[1] treated as $fallback";
                    }
                    version->new($fallback);
                  },
                },
            );
            $self->{$key} = $cmr->as_string_hash;
            $key2cmr{$key} = $cmr;
        } else {
            for my $module (sort keys %{ $self->{$key} }) {
                my $version = $self->{$key}->{$module};
                my $fallback = 0;
                if (!defined($version) or !length($version)) {
                    carp "Undefined requirement for $module treated as '0' (CPAN::Meta::Requirements not available)";
                }
                elsif ($version =~ /^\d+(?:\.\d+(?:_\d+)*)?$/) {
                    next;
                }
                else {
                    if ( $version =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
                      $fallback = sprintf "%f", $version;
                    } else {
                      ($fallback) = $version ? ($version =~ /^([0-9.]+)/) : 0;
                      $fallback += 0;
                      carp "Unparsable version '$version' for prerequisite $module treated as $fallback (CPAN::Meta::Requirements not available)";
                    }
                }
                $self->{$key}->{$module} = $fallback;
            }
        }
    }

    if ("@ARGV" =~ /\bPREREQ_PRINT\b/) {
        $self->_PREREQ_PRINT;
    }

    # PRINT_PREREQ is RedHatism.
    if ("@ARGV" =~ /\bPRINT_PREREQ\b/) {
        $self->_PRINT_PREREQ;
   }

    print "MakeMaker (v$VERSION)\n" if $Verbose;
    if (-f "MANIFEST" && ! -f "Makefile" && ! $UNDER_CORE){
        check_manifest();
    }

    check_hints($self);

    if ( $self->{MIN_PERL_VERSION}) {
        my $perl_version = $self->{MIN_PERL_VERSION};
        if (ref $perl_version) {
            # assume a version object
        }
        else {
            $perl_version = eval {
                local $SIG{__WARN__} = sub {
                    # simulate "use warnings FATAL => 'all'" for vintage perls
                    die @_;
                };
                version->new( $perl_version )->numify;
            };
            $perl_version =~ tr/_//d
                if defined $perl_version;
        }

        if (!defined $perl_version) {
            # should this be a warning?
            die sprintf <<'END', $self->{MIN_PERL_VERSION};
MakeMaker FATAL: MIN_PERL_VERSION (%s) is not in a recognized format.
Recommended is a quoted numerical value like '5.005' or '5.008001'.
END
        }
        elsif ($perl_version > "$]") {
            my $message = sprintf <<'END', $perl_version, $];
Perl version %s or higher required. We run %s.
END
            if ($self->{PREREQ_FATAL}) {
                die "MakeMaker FATAL: $message";
            }
            else {
                warn "Warning: $message";
            }
        }

        $self->{MIN_PERL_VERSION} = $perl_version;
    }

    my %configure_att;         # record &{$self->{CONFIGURE}} attributes
    my(%initial_att) = %$self; # record initial attributes

    my(%unsatisfied) = ();
    my %prereq2version;
    my $cmr;
    if (_has_cpan_meta_requirements) {
        $cmr = CPAN::Meta::Requirements->new;
        for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
            $cmr->add_requirements($key2cmr{$key}) if $key2cmr{$key};
        }
        foreach my $prereq ($cmr->required_modules) {
            $prereq2version{$prereq} = $cmr->requirements_for_module($prereq);
        }
    } else {
        for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
            next unless my $module2version = $self->{$key};
            $prereq2version{$_} = $module2version->{$_} for keys %$module2version;
        }
    }
    foreach my $prereq (sort keys %prereq2version) {
        my $required_version = $prereq2version{$prereq};

        my $pr_version = 0;
        my $installed_file;

        if ( $prereq eq 'perl' ) {
          if ( defined $required_version && $required_version =~ /^v?[\d_\.]+$/
               || $required_version !~ /^v?[\d_\.]+$/ ) {
            require version;
            my $normal = eval { version->new( $required_version ) };
            $required_version = $normal if defined $normal;
          }
          $installed_file = $prereq;
          $pr_version = $];
        }
        else {
          $installed_file = MM->_installed_file_for_module($prereq);
          $pr_version = MM->parse_version($installed_file) if $installed_file;
          $pr_version = 0 if $pr_version eq 'undef';
          if ( !eval { version->new( $pr_version ); 1 } ) {
            #no warnings 'numeric'; # module doesn't use warnings
            my $fallback;
            if ( $pr_version =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
              $fallback = sprintf '%f', $pr_version;
            } else {
              ($fallback) = $pr_version ? ($pr_version =~ /^([0-9.]+)/) : 0;
              $fallback += 0;
              carp "Unparsable version '$pr_version' for installed prerequisite $prereq treated as $fallback";
            }
            $pr_version = $fallback;
          }
        }

        # convert X.Y_Z alpha version #s to X.YZ for easier comparisons
        $pr_version =~ s/(\d+)\.(\d+)_(\d+)/$1.$2$3/;

        if (!$installed_file) {
            warn sprintf "Warning: prerequisite %s %s not found.\n",
              $prereq, $required_version
                   unless $self->{PREREQ_FATAL}
                       or $UNDER_CORE;

            $unsatisfied{$prereq} = 'not installed';
        }
        elsif (
            $cmr
                ? !$cmr->accepts_module($prereq, $pr_version)
                : $required_version > $pr_version
        ) {
            warn sprintf "Warning: prerequisite %s %s not found. We have %s.\n",
              $prereq, $required_version, ($pr_version || 'unknown version')
                  unless $self->{PREREQ_FATAL}
                       or $UNDER_CORE;

            $unsatisfied{$prereq} = $required_version || 'unknown version' ;
        }
    }

    if (%unsatisfied && $self->{PREREQ_FATAL}){
        my $failedprereqs = join "\n", map {"    $_ $unsatisfied{$_}"}
                            sort { lc $a cmp lc $b } keys %unsatisfied;
        die <<"END";
MakeMaker FATAL: prerequisites not found.
$failedprereqs

Please install these modules first and rerun 'perl Makefile.PL'.
END
    }

    if (defined $self->{CONFIGURE}) {
        if (ref $self->{CONFIGURE} eq 'CODE') {
            %configure_att = %{&{$self->{CONFIGURE}}};
            _convert_compat_attrs(\%configure_att);
            $self = { %$self, %configure_att };
        } else {
            croak "Attribute 'CONFIGURE' to WriteMakefile() not a code reference\n";
        }
    }

    my $newclass = ++$PACKNAME;
    local @Parent = @Parent;    # Protect against non-local exits
    {
        print "Blessing Object into class [$newclass]\n" if $Verbose>=2;
        mv_all_methods("MY",$newclass);
        bless $self, $newclass;
        push @Parent, $self;
        require ExtUtils::MY;

        no strict 'refs';   ## no critic;
        @{"$newclass\:\:ISA"} = 'MM';
    }

    if (defined $Parent[-2]){
        $self->{PARENT} = $Parent[-2];
        for my $key (@Prepend_parent) {
            next unless defined $self->{PARENT}{$key};

            # Don't stomp on WriteMakefile() args.
            next if defined $self->{ARGS}{$key} and
                    $self->{ARGS}{$key} eq $self->{$key};

            $self->{$key} = $self->{PARENT}{$key};

            if ($Is_VMS && $key =~ /PERL$/) {
                # PERL or FULLPERL will be a command verb or even a
                # command with an argument instead of a full file
                # specification under VMS.  So, don't turn the command
                # into a filespec, but do add a level to the path of
                # the argument if not already absolute.
                my @cmd = split /\s+/, $self->{$key};
                $cmd[1] = $self->catfile('[-]',$cmd[1])
                  unless (@cmd < 2) || $self->file_name_is_absolute($cmd[1]);
                $self->{$key} = join(' ', @cmd);
            } else {
                my $value = $self->{$key};
                # not going to test in FS so only stripping start
                $value =~ s/"// if $key =~ /PERL$/ and $self->is_make_type('dmake');
                $value =~ s/^"// if $key =~ /PERL$/;
                $value = $self->catdir("..", $value)
                  unless $self->file_name_is_absolute($value);
                $value = qq{"$value} if $key =~ /PERL$/;
                $self->{$key} = $value;
            }
        }
        if ($self->{PARENT}) {
            $self->{PARENT}->{CHILDREN}->{$newclass} = $self;
            foreach my $opt (qw(POLLUTE PERL_CORE LINKTYPE AR FULL_AR CC CCFLAGS
                                OPTIMIZE LD LDDLFLAGS LDFLAGS PERL_ARCHLIB DESTDIR)) {
                if (exists $self->{PARENT}->{$opt}
                    and not exists $self->{$opt})
                    {
                        # inherit, but only if already unspecified
                        $self->{$opt} = $self->{PARENT}->{$opt};
                    }
            }
        }
        my @fm = grep /^FIRST_MAKEFILE=/, @ARGV;
        parse_args($self,@fm) if @fm;
    }
    else {
        parse_args($self, _shellwords($ENV{PERL_MM_OPT} || ''),@ARGV);
    }

    # RT#91540 PREREQ_FATAL not recognized on command line
    if (%unsatisfied && $self->{PREREQ_FATAL}){
        my $failedprereqs = join "\n", map {"    $_ $unsatisfied{$_}"}
                            sort { lc $a cmp lc $b } keys %unsatisfied;
        die <<"END";
MakeMaker FATAL: prerequisites not found.
$failedprereqs

Please install these modules first and rerun 'perl Makefile.PL'.
END
    }

    $self->{NAME} ||= $self->guess_name;

    warn "Warning: NAME must be a package name\n"
      unless $self->{NAME} =~ m!^[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*$!;

    ($self->{NAME_SYM} = $self->{NAME}) =~ s/\W+/_/g;

    $self->init_MAKE;
    $self->init_main;
    $self->init_VERSION;
    $self->init_dist;
    $self->init_INST;
    $self->init_INSTALL;
    $self->init_DEST;
    $self->init_dirscan;
    $self->init_PM;
    $self->init_MANPODS;
    $self->init_xs;
    $self->init_PERL;
    $self->init_DIRFILESEP;
    $self->init_linker;
    $self->init_ABSTRACT;

    $self->arch_check(
        $INC{'Config.pm'},
        $self->catfile($Config{'archlibexp'}, "Config.pm")
    );

    $self->init_tools();
    $self->init_others();
    $self->init_platform();
    $self->init_PERM();
    my @args = @ARGV;
    @args = map { Encode::decode(locale => $_) } @args if $CAN_DECODE;
    my($argv) = neatvalue(\@args);
    $argv =~ s/^\[/(/;
    $argv =~ s/\]$/)/;

    push @{$self->{RESULT}}, <<END;
# This Makefile is for the $self->{NAME} extension to perl.
#
# It was generated automatically by MakeMaker version
# $VERSION (Revision: $Revision) from the contents of
# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
#
#       ANY CHANGES MADE HERE WILL BE LOST!
#
#   MakeMaker ARGV: $argv
#
END

    push @{$self->{RESULT}}, $self->_MakeMaker_Parameters_section(\%initial_att);

    if (defined $self->{CONFIGURE}) {
       push @{$self->{RESULT}}, <<END;

#   MakeMaker 'CONFIGURE' Parameters:
END
        if (scalar(keys %configure_att) > 0) {
            foreach my $key (sort keys %configure_att){
               next if $key eq 'ARGS';
               my($v) = neatvalue($configure_att{$key});
               $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/;
               $v =~ tr/\n/ /s;
               push @{$self->{RESULT}}, "#     $key => $v";
            }
        }
        else
        {
           push @{$self->{RESULT}}, "# no values returned";
        }
        undef %configure_att;  # free memory
    }

    # turn the SKIP array into a SKIPHASH hash
    for my $skip (@{$self->{SKIP} || []}) {
        $self->{SKIPHASH}{$skip} = 1;
    }
    delete $self->{SKIP}; # free memory

    if ($self->{PARENT}) {
        for (qw/install dist dist_basics dist_core distdir dist_test dist_ci/) {
            $self->{SKIPHASH}{$_} = 1;
        }
    }

    # We run all the subdirectories now. They don't have much to query
    # from the parent, but the parent has to query them: if they need linking!
    unless ($self->{NORECURS}) {
        $self->eval_in_subdirs if @{$self->{DIR}};
    }

    foreach my $section ( @MM_Sections ){
        # Support for new foo_target() methods.
        my $method = $section;
        $method .= '_target' unless $self->can($method);

        print "Processing Makefile '$section' section\n" if ($Verbose >= 2);
        my($skipit) = $self->skipcheck($section);
        if ($skipit){
            push @{$self->{RESULT}}, "\n# --- MakeMaker $section section $skipit.";
        } else {
            my(%a) = %{$self->{$section} || {}};
            push @{$self->{RESULT}}, "\n# --- MakeMaker $section section:";
            push @{$self->{RESULT}}, "# " . join ", ", %a if $Verbose && %a;
            push @{$self->{RESULT}}, $self->maketext_filter(
                $self->$method( %a )
            );
        }
    }

    push @{$self->{RESULT}}, "\n# End.";

    $self;
}

sub WriteEmptyMakefile {
    croak "WriteEmptyMakefile: Need an even number of args" if @_ % 2;

    my %att = @_;
    $att{DIR} = [] unless $att{DIR}; # don't recurse by default
    my $self = MM->new(\%att);

    my $new = $self->{MAKEFILE};
    my $old = $self->{MAKEFILE_OLD};
    if (-f $old) {
        _unlink($old) or warn "unlink $old: $!";
    }
    if ( -f $new ) {
        _rename($new, $old) or warn "rename $new => $old: $!"
    }
    open my $mfh, '>', $new or die "open $new for write: $!";
    print $mfh <<'EOP';
all :

manifypods :

subdirs :

dynamic :

static :

clean :

install :

makemakerdflt :

test :

test_dynamic :

test_static :

EOP
    close $mfh or die "close $new for write: $!";
}


=begin private

=head3 _installed_file_for_module

  my $file = MM->_installed_file_for_module($module);

Return the first installed .pm $file associated with the $module.  The
one which will show up when you C<use $module>.

$module is something like "strict" or "Test::More".

=end private

=cut

sub _installed_file_for_module {
    my $class  = shift;
    my $prereq = shift;

    my $file = "$prereq.pm";
    $file =~ s{::}{/}g;

    my $path;
    for my $dir (@INC) {
        my $tmp = File::Spec->catfile($dir, $file);
        if ( -r $tmp ) {
            $path = $tmp;
            last;
        }
    }

    return $path;
}


# Extracted from MakeMaker->new so we can test it
sub _MakeMaker_Parameters_section {
    my $self = shift;
    my $att  = shift;

    my @result = <<'END';
#   MakeMaker Parameters:
END

    foreach my $key (sort keys %$att){
        next if $key eq 'ARGS';
        my $v;
        if ($key eq 'PREREQ_PM') {
            # CPAN.pm takes prereqs from this field in 'Makefile'
            # and does not know about BUILD_REQUIRES
            $v = neatvalue({
                %{ $att->{PREREQ_PM} || {} },
                %{ $att->{BUILD_REQUIRES} || {} },
                %{ $att->{TEST_REQUIRES} || {} },
            });
        } else {
            $v = neatvalue($att->{$key});
        }

        $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/;
        $v =~ tr/\n/ /s;
        push @result, "#     $key => $v";
    }

    return @result;
}

# _shellwords and _parseline borrowed from Text::ParseWords
sub _shellwords {
    my (@lines) = @_;
    my @allwords;

    foreach my $line (@lines) {
      $line =~ s/^\s+//;
      my @words = _parse_line('\s+', 0, $line);
      pop @words if (@words and !defined $words[-1]);
      return() unless (@words || !length($line));
      push(@allwords, @words);
    }
    return(@allwords);
}

sub _parse_line {
    my($delimiter, $keep, $line) = @_;
    my($word, @pieces);

    no warnings 'uninitialized';  # we will be testing undef strings

    while (length($line)) {
        # This pattern is optimised to be stack conservative on older perls.
        # Do not refactor without being careful and testing it on very long strings.
        # See Perl bug #42980 for an example of a stack busting input.
        $line =~ s/^
                    (?:
                        # double quoted string
                        (")                             # $quote
                        ((?>[^\\"]*(?:\\.[^\\"]*)*))"   # $quoted
        | # --OR--
                        # singe quoted string
                        (')                             # $quote
                        ((?>[^\\']*(?:\\.[^\\']*)*))'   # $quoted
                    |   # --OR--
                        # unquoted string
            (                               # $unquoted
                            (?:\\.|[^\\"'])*?
                        )
                        # followed by
            (                               # $delim
                            \Z(?!\n)                    # EOL
                        |   # --OR--
                            (?-x:$delimiter)            # delimiter
                        |   # --OR--
                            (?!^)(?=["'])               # a quote
                        )
        )//xs or return;    # extended layout
        my ($quote, $quoted, $unquoted, $delim) = (($1 ? ($1,$2) : ($3,$4)), $5, $6);


  return() unless( defined($quote) || length($unquoted) || length($delim));

        if ($keep) {
      $quoted = "$quote$quoted$quote";
  }
        else {
      $unquoted =~ s/\\(.)/$1/sg;
      if (defined $quote) {
    $quoted =~ s/\\(.)/$1/sg if ($quote eq '"');
    #$quoted =~ s/\\([\\'])/$1/g if ( $PERL_SINGLE_QUOTE && $quote eq "'");
            }
  }
        $word .= substr($line, 0, 0); # leave results tainted
        $word .= defined $quote ? $quoted : $unquoted;

        if (length($delim)) {
            push(@pieces, $word);
            push(@pieces, $delim) if ($keep eq 'delimiters');
            undef $word;
        }
        if (!length($line)) {
            push(@pieces, $word);
  }
    }
    return(@pieces);
}

sub check_manifest {
    print STDOUT "Checking if your kit is complete...\n";
    require ExtUtils::Manifest;
    # avoid warning
    $ExtUtils::Manifest::Quiet = $ExtUtils::Manifest::Quiet = 1;
    my(@missed) = ExtUtils::Manifest::manicheck();
    if (@missed) {
        print "Warning: the following files are missing in your kit:\n";
        print "\t", join "\n\t", @missed;
        print "\n";
        print "Please inform the author.\n";
    } else {
        print "Looks good\n";
    }
}

sub parse_args{
    my($self, @args) = @_;
    @args = map { Encode::decode(locale => $_) } @args if $CAN_DECODE;
    foreach (@args) {
        unless (m/(.*?)=(.*)/) {
            ++$Verbose if m/^verb/;
            next;
        }
        my($name, $value) = ($1, $2);
        if ($value =~ m/^~(\w+)?/) { # tilde with optional username
            $value =~ s [^~(\w*)]
                [$1 ?
                 ((getpwnam($1))[7] || "~$1") :
                 (getpwuid($>))[7]
                 ]ex;
        }

        # Remember the original args passed it.  It will be useful later.
        $self->{ARGS}{uc $name} = $self->{uc $name} = $value;
    }

    # catch old-style 'potential_libs' and inform user how to 'upgrade'
    if (defined $self->{potential_libs}){
        my($msg)="'potential_libs' => '$self->{potential_libs}' should be";
        if ($self->{potential_libs}){
            print "$msg changed to:\n\t'LIBS' => ['$self->{potential_libs}']\n";
        } else {
            print "$msg deleted.\n";
        }
        $self->{LIBS} = [$self->{potential_libs}];
        delete $self->{potential_libs};
    }
    # catch old-style 'ARMAYBE' and inform user how to 'upgrade'
    if (defined $self->{ARMAYBE}){
        my($armaybe) = $self->{ARMAYBE};
        print "ARMAYBE => '$armaybe' should be changed to:\n",
                        "\t'dynamic_lib' => {ARMAYBE => '$armaybe'}\n";
        my(%dl) = %{$self->{dynamic_lib} || {}};
        $self->{dynamic_lib} = { %dl, ARMAYBE => $armaybe};
        delete $self->{ARMAYBE};
    }
    if (defined $self->{LDTARGET}){
        print "LDTARGET should be changed to LDFROM\n";
        $self->{LDFROM} = $self->{LDTARGET};
        delete $self->{LDTARGET};
    }
    # Turn a DIR argument on the command line into an array
    if (defined $self->{DIR} && ref \$self->{DIR} eq 'SCALAR') {
        # So they can choose from the command line, which extensions they want
        # the grep enables them to have some colons too much in case they
        # have to build a list with the shell
        $self->{DIR} = [grep $_, split ":", $self->{DIR}];
    }
    # Turn a INCLUDE_EXT argument on the command line into an array
    if (defined $self->{INCLUDE_EXT} && ref \$self->{INCLUDE_EXT} eq 'SCALAR') {
        $self->{INCLUDE_EXT} = [grep $_, split '\s+', $self->{INCLUDE_EXT}];
    }
    # Turn a EXCLUDE_EXT argument on the command line into an array
    if (defined $self->{EXCLUDE_EXT} && ref \$self->{EXCLUDE_EXT} eq 'SCALAR') {
        $self->{EXCLUDE_EXT} = [grep $_, split '\s+', $self->{EXCLUDE_EXT}];
    }

    foreach my $mmkey (sort keys %$self){
        next if $mmkey eq 'ARGS';
        print "  $mmkey => ", neatvalue($self->{$mmkey}), "\n" if $Verbose;
        print "'$mmkey' is not a known MakeMaker parameter name.\n"
            unless exists $Recognized_Att_Keys{$mmkey};
    }
    $| = 1 if $Verbose;
}

sub check_hints {
    my($self) = @_;
    # We allow extension-specific hints files.

    require File::Spec;
    my $curdir = File::Spec->curdir;

    my $hint_dir = File::Spec->catdir($curdir, "hints");
    return unless -d $hint_dir;

    # First we look for the best hintsfile we have
    my($hint)="${^O}_$Config{osvers}";
    $hint =~ s/\./_/g;
    $hint =~ s/_$//;
    return unless $hint;

    # Also try without trailing minor version numbers.
    while (1) {
        last if -f File::Spec->catfile($hint_dir, "$hint.pl");  # found
    } continue {
        last unless $hint =~ s/_[^_]*$//; # nothing to cut off
    }
    my $hint_file = File::Spec->catfile($hint_dir, "$hint.pl");

    return unless -f $hint_file;    # really there

    _run_hintfile($self, $hint_file);
}

sub _run_hintfile {
    my ($self, $hint_file) = @_;

    local($@, $!);
    print "Processing hints file $hint_file\n" if $Verbose;

    if(open(my $fh, '<', $hint_file)) {
        my $hints_content = do { local $/; <$fh> };
        no strict;
        eval $hints_content;
        warn "Failed to run hint file $hint_file: $@" if $@;
    }
    else {
        warn "Could not open $hint_file for read: $!";
    }
}

sub mv_all_methods {
    my($from,$to) = @_;
    local $SIG{__WARN__} = sub {
        # can't use 'no warnings redefined', 5.6 only
        warn @_ unless $_[0] =~ /^Subroutine .* redefined/
    };
    foreach my $method (@Overridable) {
        next unless defined &{"${from}::$method"};
        no strict 'refs';   ## no critic
        *{"${to}::$method"} = \&{"${from}::$method"};

        # If we delete a method, then it will be undefined and cannot
        # be called.  But as long as we have Makefile.PLs that rely on
        # %MY:: being intact, we have to fill the hole with an
        # inheriting method:

        {
            package MY;
            my $super = "SUPER::".$method;
            *{$method} = sub {
                shift->$super(@_);
            };
        }
    }
}

sub skipcheck {
    my($self) = shift;
    my($section) = @_;
    return 'skipped' if $section eq 'metafile' && $UNDER_CORE;
    if ($section eq 'dynamic') {
        print "Warning (non-fatal): Target 'dynamic' depends on targets ",
        "in skipped section 'dynamic_bs'\n"
            if $self->{SKIPHASH}{dynamic_bs} && $Verbose;
        print "Warning (non-fatal): Target 'dynamic' depends on targets ",
        "in skipped section 'dynamic_lib'\n"
            if $self->{SKIPHASH}{dynamic_lib} && $Verbose;
    }
    if ($section eq 'dynamic_lib') {
        print "Warning (non-fatal): Target '\$(INST_DYNAMIC)' depends on ",
        "targets in skipped section 'dynamic_bs'\n"
            if $self->{SKIPHASH}{dynamic_bs} && $Verbose;
    }
    if ($section eq 'static') {
        print "Warning (non-fatal): Target 'static' depends on targets ",
        "in skipped section 'static_lib'\n"
            if $self->{SKIPHASH}{static_lib} && $Verbose;
    }
    return 'skipped' if $self->{SKIPHASH}{$section};
    return '';
}

# returns filehandle, dies on fail. :raw so no :crlf
sub open_for_writing {
    my ($file) = @_;
    open my $fh ,">", $file or die "Unable to open $file: $!";
    my @layers = ':raw';
    push @layers, join ' ', ':encoding(locale)' if $CAN_DECODE;
    binmode $fh, join ' ', @layers;
    $fh;
}

sub flush {
    my $self = shift;

    my $finalname = $self->{MAKEFILE};
    printf STDOUT "Generating a %s %s\n", $self->make_type, $finalname if $Verbose || !$self->{PARENT};
    print STDOUT "Writing $finalname for $self->{NAME}\n" if $Verbose || !$self->{PARENT};

    unlink($finalname, "MakeMaker.tmp", $Is_VMS ? 'Descrip.MMS' : ());

    write_file_via_tmp($finalname, $self->{RESULT});

    # Write MYMETA.yml to communicate metadata up to the CPAN clients
    print STDOUT "Writing MYMETA.yml and MYMETA.json\n"
      if !$self->{NO_MYMETA} and $self->write_mymeta( $self->mymeta );

    # save memory
    if ($self->{PARENT} && !$self->{_KEEP_AFTER_FLUSH}) {
        my %keep = map { ($_ => 1) } qw(NEEDS_LINKING HAS_LINK_CODE);
        delete $self->{$_} for grep !$keep{$_}, keys %$self;
    }

    system("$Config::Config{eunicefix} $finalname")
      if $Config::Config{eunicefix} ne ":";

    return;
}

sub write_file_via_tmp {
    my ($finalname, $contents) = @_;
    my $fh = open_for_writing("MakeMaker.tmp");
    die "write_file_via_tmp: 2nd arg must be ref" unless ref $contents;
    for my $chunk (@$contents) {
        my $to_write = $chunk;
        utf8::encode $to_write if !$CAN_DECODE && "$]" > 5.008;
        print $fh "$to_write\n" or die "Can't write to MakeMaker.tmp: $!";
    }
    close $fh or die "Can't write to MakeMaker.tmp: $!";
    _rename("MakeMaker.tmp", $finalname) or
      warn "rename MakeMaker.tmp => $finalname: $!";
    chmod 0644, $finalname if !$Is_VMS;
    return;
}

# This is a rename for OS's where the target must be unlinked first.
sub _rename {
    my($src, $dest) = @_;
    _unlink($dest);
    return rename $src, $dest;
}

# This is an unlink for OS's where the target must be writable first.
sub _unlink {
    my @files = @_;
    chmod 0666, @files;
    return unlink @files;
}


# The following mkbootstrap() is only for installations that are calling
# the pre-4.1 mkbootstrap() from their old Makefiles. This MakeMaker
# writes Makefiles, that use ExtUtils::Mkbootstrap directly.
sub mkbootstrap {
    die <<END;
!!! Your Makefile has been built such a long time ago, !!!
!!! that is unlikely to work with current MakeMaker.   !!!
!!! Please rebuild your Makefile                       !!!
END
}

# Ditto for mksymlists() as of MakeMaker 5.17
sub mksymlists {
    die <<END;
!!! Your Makefile has been built such a long time ago, !!!
!!! that is unlikely to work with current MakeMaker.   !!!
!!! Please rebuild your Makefile                       !!!
END
}

sub neatvalue {
    my($v) = @_;
    return "undef" unless defined $v;
    my($t) = ref $v;
    return "q[$v]" unless $t;
    if ($t eq 'ARRAY') {
        my(@m, @neat);
        push @m, "[";
        foreach my $elem (@$v) {
            push @neat, "q[$elem]";
        }
        push @m, join ", ", @neat;
        push @m, "]";
        return join "", @m;
    }
    return $v unless $t eq 'HASH';
    my(@m, $key, $val);
    for my $key (sort keys %$v) {
        last unless defined $key; # cautious programming in case (undef,undef) is true
        push @m,"$key=>".neatvalue($v->{$key});
    }
    return "{ ".join(', ',@m)." }";
}

sub _find_magic_vstring {
    my $value = shift;
    return $value if $UNDER_CORE;
    my $tvalue = '';
    require B;
    my $sv = B::svref_2object(\$value);
    my $magic = ref($sv) eq 'B::PVMG' ? $sv->MAGIC : undef;
    while ( $magic ) {
        if ( $magic->TYPE eq 'V' ) {
            $tvalue = $magic->PTR;
            $tvalue =~ s/^v?(.+)$/v$1/;
            last;
        }
        else {
            $magic = $magic->MOREMAGIC;
        }
    }
    return $tvalue;
}

sub selfdocument {
    my($self) = @_;
    my(@m);
    if ($Verbose){
        push @m, "\n# Full list of MakeMaker attribute values:";
        foreach my $key (sort keys %$self){
            next if $key eq 'RESULT' || $key =~ /^[A-Z][a-z]/;
            my($v) = neatvalue($self->{$key});
            $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/;
            $v =~ tr/\n/ /s;
            push @m, "# $key => $v";
        }
    }
    # added here as selfdocument is not overridable
    push @m, <<'EOF';

# here so even if top_targets is overridden, these will still be defined
# gmake will silently still work if any are .PHONY-ed but nmake won't
EOF
    push @m, join "\n", map "$_ ::\n\t\$(NOECHO) \$(NOOP)\n",
        # config is so manifypods won't puke if no subdirs
        grep !$self->{SKIPHASH}{$_},
        qw(static dynamic config);
    join "\n", @m;
}

1;

__END__

=head1 NAME

ExtUtils::MakeMaker - Create a module Makefile

=head1 SYNOPSIS

  use ExtUtils::MakeMaker;

  WriteMakefile(
      NAME              => "Foo::Bar",
      VERSION_FROM      => "lib/Foo/Bar.pm",
  );

=head1 DESCRIPTION

This utility is designed to write a Makefile for an extension module
from a Makefile.PL. It is based on the Makefile.SH model provided by
Andy Dougherty and the perl5-porters.

It splits the task of generating the Makefile into several subroutines
that can be individually overridden.  Each subroutine returns the text
it wishes to have written to the Makefile.

As there are various Make programs with incompatible syntax, which
use operating system shells, again with incompatible syntax, it is
important for users of this module to know which flavour of Make
a Makefile has been written for so they'll use the correct one and
won't have to face the possibly bewildering errors resulting from
using the wrong one.

On POSIX systems, that program will likely be GNU Make; on Microsoft
Windows, it will be either Microsoft NMake, DMake or GNU Make.
See the section on the L</"MAKE"> parameter for details.

ExtUtils::MakeMaker (EUMM) is object oriented. Each directory below the current
directory that contains a Makefile.PL is treated as a separate
object. This makes it possible to write an unlimited number of
Makefiles with a single invocation of WriteMakefile().

All inputs to WriteMakefile are Unicode characters, not just octets. EUMM
seeks to handle all of these correctly. It is currently still not possible
to portably use Unicode characters in module names, because this requires
Perl to handle Unicode filenames, which is not yet the case on Windows.

See L<ExtUtils::MakeMaker::FAQ> for details of the design and usage.

=head2 How To Write A Makefile.PL

See L<ExtUtils::MakeMaker::Tutorial>.

The long answer is the rest of the manpage :-)

=head2 Default Makefile Behaviour

The generated Makefile enables the user of the extension to invoke

  perl Makefile.PL # optionally "perl Makefile.PL verbose"
  make
  make test        # optionally set TEST_VERBOSE=1
  make install     # See below

The Makefile to be produced may be altered by adding arguments of the
form C<KEY=VALUE>. E.g.

  perl Makefile.PL INSTALL_BASE=~

Other interesting targets in the generated Makefile are

  make config     # to check if the Makefile is up-to-date
  make clean      # delete local temp files (Makefile gets renamed)
  make realclean  # delete derived files (including ./blib)
  make ci         # check in all the files in the MANIFEST file
  make dist       # see below the Distribution Support section

=head2 make test

MakeMaker checks for the existence of a file named F<test.pl> in the
current directory, and if it exists it executes the script with the
proper set of perl C<-I> options.

MakeMaker also checks for any files matching glob("t/*.t"). It will
execute all matching files in alphabetical order via the
L<Test::Harness> module with the C<-I> switches set correctly.

You can also organize your tests within subdirectories in the F<t/> directory.
To do so, use the F<test> directive in your I<Makefile.PL>. For example, if you
had tests in:

    t/foo
    t/foo/bar

You could tell make to run tests in both of those directories with the
following directives:

    test => {TESTS => 't/*/*.t t/*/*/*.t'}
    test => {TESTS => 't/foo/*.t t/foo/bar/*.t'}

The first will run all test files in all first-level subdirectories and all
subdirectories they contain. The second will run tests in only the F<t/foo>
and F<t/foo/bar>.

If you'd like to see the raw output of your tests, set the
C<TEST_VERBOSE> variable to true.

  make test TEST_VERBOSE=1

If you want to run particular test files, set the C<TEST_FILES> variable.
It is possible to use globbing with this mechanism.

  make test TEST_FILES='t/foobar.t t/dagobah*.t'

Windows users who are using C<nmake> should note that due to a bug in C<nmake>,
when specifying C<TEST_FILES> you must use back-slashes instead of forward-slashes.

  nmake test TEST_FILES='t\foobar.t t\dagobah*.t'

=head2 make testdb

A useful variation of the above is the target C<testdb>. It runs the
test under the Perl debugger (see L<perldebug>). If the file
F<test.pl> exists in the current directory, it is used for the test.

If you want to debug some other testfile, set the C<TEST_FILE> variable
thusly:

  make testdb TEST_FILE=t/mytest.t

By default the debugger is called using C<-d> option to perl. If you
want to specify some other option, set the C<TESTDB_SW> variable:

  make testdb TESTDB_SW=-Dx

=head2 make install

make alone puts all relevant files into directories that are named by
the macros INST_LIB, INST_ARCHLIB, INST_SCRIPT, INST_MAN1DIR and
INST_MAN3DIR.  All these default to something below ./blib if you are
I<not> building below the perl source directory. If you I<are>
building below the perl source, INST_LIB and INST_ARCHLIB default to
../../lib, and INST_SCRIPT is not defined.

The I<install> target of the generated Makefile copies the files found
below each of the INST_* directories to their INSTALL*
counterparts. Which counterparts are chosen depends on the setting of
INSTALLDIRS according to the following table:

                                 INSTALLDIRS set to
                           perl        site          vendor

                 PERLPREFIX      SITEPREFIX          VENDORPREFIX
  INST_ARCHLIB   INSTALLARCHLIB  INSTALLSITEARCH     INSTALLVENDORARCH
  INST_LIB       INSTALLPRIVLIB  INSTALLSITELIB      INSTALLVENDORLIB
  INST_BIN       INSTALLBIN      INSTALLSITEBIN      INSTALLVENDORBIN
  INST_SCRIPT    INSTALLSCRIPT   INSTALLSITESCRIPT   INSTALLVENDORSCRIPT
  INST_MAN1DIR   INSTALLMAN1DIR  INSTALLSITEMAN1DIR  INSTALLVENDORMAN1DIR
  INST_MAN3DIR   INSTALLMAN3DIR  INSTALLSITEMAN3DIR  INSTALLVENDORMAN3DIR

The INSTALL... macros in turn default to their %Config
($Config{installprivlib}, $Config{installarchlib}, etc.) counterparts.

You can check the values of these variables on your system with

    perl '-V:install.*'

And to check the sequence in which the library directories are
searched by perl, run

    perl -le 'print join $/, @INC'

Sometimes older versions of the module you're installing live in other
directories in @INC.  Because Perl loads the first version of a module it
finds, not the newest, you might accidentally get one of these older
versions even after installing a brand new version.  To delete I<all other
versions of the module you're installing> (not simply older ones) set the
C<UNINST> variable.

    make install UNINST=1


=head2 INSTALL_BASE

INSTALL_BASE can be passed into Makefile.PL to change where your
module will be installed.  INSTALL_BASE is more like what everyone
else calls "prefix" than PREFIX is.

To have everything installed in your home directory, do the following.

    # Unix users, INSTALL_BASE=~ works fine
    perl Makefile.PL INSTALL_BASE=/path/to/your/home/dir

Like PREFIX, it sets several INSTALL* attributes at once.  Unlike
PREFIX it is easy to predict where the module will end up.  The
installation pattern looks like this:

    INSTALLARCHLIB     INSTALL_BASE/lib/perl5/$Config{archname}
    INSTALLPRIVLIB     INSTALL_BASE/lib/perl5
    INSTALLBIN         INSTALL_BASE/bin
    INSTALLSCRIPT      INSTALL_BASE/bin
    INSTALLMAN1DIR     INSTALL_BASE/man/man1
    INSTALLMAN3DIR     INSTALL_BASE/man/man3

INSTALL_BASE in MakeMaker and C<--install_base> in Module::Build (as
of 0.28) install to the same location.  If you want MakeMaker and
Module::Build to install to the same location simply set INSTALL_BASE
and C<--install_base> to the same location.

INSTALL_BASE was added in 6.31.


=head2 PREFIX and LIB attribute

PREFIX and LIB can be used to set several INSTALL* attributes in one
go.  Here's an example for installing into your home directory.

    # Unix users, PREFIX=~ works fine
    perl Makefile.PL PREFIX=/path/to/your/home/dir

This will install all files in the module under your home directory,
with man pages and libraries going into an appropriate place (usually
~/man and ~/lib).  How the exact location is determined is complicated
and depends on how your Perl was configured.  INSTALL_BASE works more
like what other build systems call "prefix" than PREFIX and we
recommend you use that instead.

Another way to specify many INSTALL directories with a single
parameter is LIB.

    perl Makefile.PL LIB=~/lib

This will install the module's architecture-independent files into
~/lib, the architecture-dependent files into ~/lib/$archname.

Note, that in both cases the tilde expansion is done by MakeMaker, not
by perl by default, nor by make.

Conflicts between parameters LIB, PREFIX and the various INSTALL*
arguments are resolved so that:

=over 4

=item *

setting LIB overrides any setting of INSTALLPRIVLIB, INSTALLARCHLIB,
INSTALLSITELIB, INSTALLSITEARCH (and they are not affected by PREFIX);

=item *

without LIB, setting PREFIX replaces the initial C<$Config{prefix}>
part of those INSTALL* arguments, even if the latter are explicitly
set (but are set to still start with C<$Config{prefix}>).

=back

If the user has superuser privileges, and is not working on AFS or
relatives, then the defaults for INSTALLPRIVLIB, INSTALLARCHLIB,
INSTALLSCRIPT, etc. will be appropriate, and this incantation will be
the best:

    perl Makefile.PL;
    make;
    make test
    make install

make install by default writes some documentation of what has been
done into the file C<$(INSTALLARCHLIB)/perllocal.pod>. This feature
can be bypassed by calling make pure_install.

=head2 AFS users

will have to specify the installation directories as these most
probably have changed since perl itself has been installed. They will
have to do this by calling

    perl Makefile.PL INSTALLSITELIB=/afs/here/today \
        INSTALLSCRIPT=/afs/there/now INSTALLMAN3DIR=/afs/for/manpages
    make

Be careful to repeat this procedure every time you recompile an
extension, unless you are sure the AFS installation directories are
still valid.

=head2 Static Linking of a new Perl Binary

An extension that is built with the above steps is ready to use on
systems supporting dynamic loading. On systems that do not support
dynamic loading, any newly created extension has to be linked together
with the available resources. MakeMaker supports the linking process
by creating appropriate targets in the Makefile whenever an extension
is built. You can invoke the corresponding section of the makefile with

    make perl

That produces a new perl binary in the current directory with all
extensions linked in that can be found in INST_ARCHLIB, SITELIBEXP,
and PERL_ARCHLIB. To do that, MakeMaker writes a new Makefile, on
UNIX, this is called F<Makefile.aperl> (may be system dependent). If you
want to force the creation of a new perl, it is recommended that you
delete this F<Makefile.aperl>, so the directories are searched through
for linkable libraries again.

The binary can be installed into the directory where perl normally
resides on your machine with

    make inst_perl

To produce a perl binary with a different name than C<perl>, either say

    perl Makefile.PL MAP_TARGET=myperl
    make myperl
    make inst_perl

or say

    perl Makefile.PL
    make myperl MAP_TARGET=myperl
    make inst_perl MAP_TARGET=myperl

In any case you will be prompted with the correct invocation of the
C<inst_perl> target that installs the new binary into INSTALLBIN.

make inst_perl by default writes some documentation of what has been
done into the file C<$(INSTALLARCHLIB)/perllocal.pod>. This
can be bypassed by calling make pure_inst_perl.

Warning: the inst_perl: target will most probably overwrite your
existing perl binary. Use with care!

Sometimes you might want to build a statically linked perl although
your system supports dynamic loading. In this case you may explicitly
set the linktype with the invocation of the Makefile.PL or make:

    perl Makefile.PL LINKTYPE=static    # recommended

or

    make LINKTYPE=static                # works on most systems

=head2 Determination of Perl Library and Installation Locations

MakeMaker needs to know, or to guess, where certain things are
located.  Especially INST_LIB and INST_ARCHLIB (where to put the files
during the make(1) run), PERL_LIB and PERL_ARCHLIB (where to read
existing modules from), and PERL_INC (header files and C<libperl*.*>).

Extensions may be built either using the contents of the perl source
directory tree or from the installed perl library. The recommended way
is to build extensions after you have run 'make install' on perl
itself. You can do that in any directory on your hard disk that is not
below the perl source tree. The support for extensions below the ext
directory of the perl distribution is only good for the standard
extensions that come with perl.

If an extension is being built below the C<ext/> directory of the perl
source then MakeMaker will set PERL_SRC automatically (e.g.,
C<../..>).  If PERL_SRC is defined and the extension is recognized as
a standard extension, then other variables default to the following:

  PERL_INC     = PERL_SRC
  PERL_LIB     = PERL_SRC/lib
  PERL_ARCHLIB = PERL_SRC/lib
  INST_LIB     = PERL_LIB
  INST_ARCHLIB = PERL_ARCHLIB

If an extension is being built away from the perl source then MakeMaker
will leave PERL_SRC undefined and default to using the installed copy
of the perl library. The other variables default to the following:

  PERL_INC     = $archlibexp/CORE
  PERL_LIB     = $privlibexp
  PERL_ARCHLIB = $archlibexp
  INST_LIB     = ./blib/lib
  INST_ARCHLIB = ./blib/arch

If perl has not yet been installed then PERL_SRC can be defined on the
command line as shown in the previous section.


=head2 Which architecture dependent directory?

If you don't want to keep the defaults for the INSTALL* macros,
MakeMaker helps you to minimize the typing needed: the usual
relationship between INSTALLPRIVLIB and INSTALLARCHLIB is determined
by Configure at perl compilation time. MakeMaker supports the user who
sets INSTALLPRIVLIB. If INSTALLPRIVLIB is set, but INSTALLARCHLIB not,
then MakeMaker defaults the latter to be the same subdirectory of
INSTALLPRIVLIB as Configure decided for the counterparts in %Config,
otherwise it defaults to INSTALLPRIVLIB. The same relationship holds
for INSTALLSITELIB and INSTALLSITEARCH.

MakeMaker gives you much more freedom than needed to configure
internal variables and get different results. It is worth mentioning
that make(1) also lets you configure most of the variables that are
used in the Makefile. But in the majority of situations this will not
be necessary, and should only be done if the author of a package
recommends it (or you know what you're doing).

=head2 Using Attributes and Parameters

The following attributes may be specified as arguments to WriteMakefile()
or as NAME=VALUE pairs on the command line. Attributes that became
available with later versions of MakeMaker are indicated.

In order to maintain portability of attributes with older versions of
MakeMaker you may want to use L<App::EUMM::Upgrade> with your C<Makefile.PL>.

=over 2

=item ABSTRACT

One line description of the module. Will be included in PPD file.

=item ABSTRACT_FROM

Name of the file that contains the package description. MakeMaker looks
for a line in the POD matching /^($package\s-\s)(.*)/. This is typically
the first line in the "=head1 NAME" section. $2 becomes the abstract.

=item AUTHOR

Array of strings containing name (and email address) of package author(s).
Is used in CPAN Meta files (META.yml or META.json) and PPD
(Perl Package Description) files for PPM (Perl Package Manager).

=item BINARY_LOCATION

Used when creating PPD files for binary packages.  It can be set to a
full or relative path or URL to the binary archive for a particular
architecture.  For example:

        perl Makefile.PL BINARY_LOCATION=x86/Agent.tar.gz

builds a PPD package that references a binary of the C<Agent> package,
located in the C<x86> directory relative to the PPD itself.

=item BUILD_REQUIRES

Available in version 6.55_03 and above.

A hash of modules that are needed to build your module but not run it.

This will go into the C<build_requires> field of your F<META.yml> and the C<build> of the C<prereqs> field of your F<META.json>.

Defaults to C<<< { "ExtUtils::MakeMaker" => 0 } >>> if this attribute is not specified.

The format is the same as PREREQ_PM.

=item C

Ref to array of *.c file names. Initialised from a directory scan
and the values portion of the XS attribute hash. This is not
currently used by MakeMaker but may be handy in Makefile.PLs.

=item CCFLAGS

String that will be included in the compiler call command line between
the arguments INC and OPTIMIZE. Note that setting this will overwrite its
default value (C<$Config::Config{ccflags}>); to preserve that, include
the default value directly, e.g.:

    CCFLAGS => "$Config::Config{ccflags} ..."

The default value is taken from $Config{ccflags}. When overriding
CCFLAGS, make sure to include the $Config{ccflags} settings to avoid
binary incompatibilities.

=item CONFIG

Arrayref. E.g. [qw(archname manext)] defines ARCHNAME & MANEXT from
config.sh. MakeMaker will add to CONFIG the following values anyway:
ar
cc
cccdlflags
ccdlflags
cpprun
dlext
dlsrc
ld
lddlflags
ldflags
libc
lib_ext
obj_ext
ranlib
sitelibexp
sitearchexp
so

=item CONFIGURE

CODE reference. The subroutine should return a hash reference. The
hash may contain further attributes, e.g. {LIBS =E<gt> ...}, that have to
be determined by some evaluation method.

=item CONFIGURE_REQUIRES

Available in version 6.52 and above.

A hash of modules that are required to run Makefile.PL itself, but not
to run your distribution.

This will go into the C<configure_requires> field of your F<META.yml> and the C<configure> of the C<prereqs> field of your F<META.json>.

Defaults to C<<< { "ExtUtils::MakeMaker" => 0 } >>> if this attribute is not specified.

The format is the same as PREREQ_PM.

=item DEFINE

Something like C<"-DHAVE_UNISTD_H">

=item DESTDIR

This is the root directory into which the code will be installed.  It
I<prepends itself to the normal prefix>.  For example, if your code
would normally go into F</usr/local/lib/perl> you could set DESTDIR=~/tmp/
and installation would go into F<~/tmp/usr/local/lib/perl>.

This is primarily of use for people who repackage Perl modules.

NOTE: Due to the nature of make, it is important that you put the trailing
slash on your DESTDIR.  F<~/tmp/> not F<~/tmp>.

=item DIR

Ref to array of subdirectories containing Makefile.PLs e.g. ['sdbm']
in ext/SDBM_File

=item DISTNAME

A safe filename for the package.

Defaults to NAME below but with :: replaced with -.

For example, Foo::Bar becomes Foo-Bar.

=item DISTVNAME

Your name for distributing the package with the version number
included.  This is used by 'make dist' to name the resulting archive
file.

Defaults to DISTNAME-VERSION.

For example, version 1.04 of Foo::Bar becomes Foo-Bar-1.04.

On some OS's where . has special meaning VERSION_SYM may be used in
place of VERSION.

=item DLEXT

Specifies the extension of the module's loadable object. For example:

  DLEXT => 'unusual_ext', # Default value is $Config{so}

NOTE: When using this option to alter the extension of a module's
loadable object, it is also necessary that the module's pm file
specifies the same change:

  local $DynaLoader::dl_dlext = 'unusual_ext';

=item DL_FUNCS

Hashref of symbol names for routines to be made available as universal
symbols.  Each key/value pair consists of the package name and an
array of routine names in that package.  Used only under AIX, OS/2,
VMS and Win32 at present.  The routine names supplied will be expanded
in the same way as XSUB names are expanded by the XS() macro.
Defaults to

  {"$(NAME)" => ["boot_$(NAME)" ] }

e.g.

  {"RPC" => [qw( boot_rpcb rpcb_gettime getnetconfigent )],
   "NetconfigPtr" => [ 'DESTROY'] }

Please see the L<ExtUtils::Mksymlists> documentation for more information
about the DL_FUNCS, DL_VARS and FUNCLIST attributes.

=item DL_VARS

Array of symbol names for variables to be made available as universal symbols.
Used only under AIX, OS/2, VMS and Win32 at present.  Defaults to [].
(e.g. [ qw(Foo_version Foo_numstreams Foo_tree ) ])

=item EXCLUDE_EXT

Array of extension names to exclude when doing a static build.  This
is ignored if INCLUDE_EXT is present.  Consult INCLUDE_EXT for more
details.  (e.g.  [ qw( Socket POSIX ) ] )

This attribute may be most useful when specified as a string on the
command line:  perl Makefile.PL EXCLUDE_EXT='Socket Safe'

=item EXE_FILES

Ref to array of executable files. The files will be copied to the
INST_SCRIPT directory. Make realclean will delete them from there
again.

If your executables start with something like #!perl or
#!/usr/bin/perl MakeMaker will change this to the path of the perl
'Makefile.PL' was invoked with so the programs will be sure to run
properly even if perl is not in /usr/bin/perl.

=item FIRST_MAKEFILE

The name of the Makefile to be produced.  This is used for the second
Makefile that will be produced for the MAP_TARGET.

Defaults to 'Makefile' or 'Descrip.MMS' on VMS.

(Note: we couldn't use MAKEFILE because dmake uses this for something
else).

=item FULLPERL

Perl binary able to run this extension, load XS modules, etc...

=item FULLPERLRUN

Like PERLRUN, except it uses FULLPERL.

=item FULLPERLRUNINST

Like PERLRUNINST, except it uses FULLPERL.

=item FUNCLIST

This provides an alternate means to specify function names to be
exported from the extension.  Its value is a reference to an
array of function names to be exported by the extension.  These
names are passed through unaltered to the linker options file.

=item H

Ref to array of *.h file names. Similar to C.

=item IMPORTS

This attribute is used to specify names to be imported into the
extension. Takes a hash ref.

It is only used on OS/2 and Win32.

=item INC

Include file dirs eg: C<"-I/usr/5include -I/path/to/inc">

=item INCLUDE_EXT

Array of extension names to be included when doing a static build.
MakeMaker will normally build with all of the installed extensions when
doing a static build, and that is usually the desired behavior.  If
INCLUDE_EXT is present then MakeMaker will build only with those extensions
which are explicitly mentioned. (e.g.  [ qw( Socket POSIX ) ])

It is not necessary to mention DynaLoader or the current extension when
filling in INCLUDE_EXT.  If the INCLUDE_EXT is mentioned but is empty then
only DynaLoader and the current extension will be included in the build.

This attribute may be most useful when specified as a string on the
command line:  perl Makefile.PL INCLUDE_EXT='POSIX Socket Devel::Peek'

=item INSTALLARCHLIB

Used by 'make install', which copies files from INST_ARCHLIB to this
directory if INSTALLDIRS is set to perl.

=item INSTALLBIN

Directory to install binary files (e.g. tkperl) into if
INSTALLDIRS=perl.

=item INSTALLDIRS

Determines which of the sets of installation directories to choose:
perl, site or vendor.  Defaults to site.

=item INSTALLMAN1DIR

=item INSTALLMAN3DIR

These directories get the man pages at 'make install' time if
INSTALLDIRS=perl.  Defaults to $Config{installman*dir}.

If set to 'none', no man pages will be installed.

=item INSTALLPRIVLIB

Used by 'make install', which copies files from INST_LIB to this
directory if INSTALLDIRS is set to perl.

Defaults to $Config{installprivlib}.

=item INSTALLSCRIPT

Available in version 6.30_02 and above.

Used by 'make install' which copies files from INST_SCRIPT to this
directory if INSTALLDIRS=perl.

=item INSTALLSITEARCH

Used by 'make install', which copies files from INST_ARCHLIB to this
directory if INSTALLDIRS is set to site (default).

=item INSTALLSITEBIN

Used by 'make install', which copies files from INST_BIN to this
directory if INSTALLDIRS is set to site (default).

=item INSTALLSITELIB

Used by 'make install', which copies files from INST_LIB to this
directory if INSTALLDIRS is set to site (default).

=item INSTALLSITEMAN1DIR

=item INSTALLSITEMAN3DIR

These directories get the man pages at 'make install' time if
INSTALLDIRS=site (default).  Defaults to
$(SITEPREFIX)/man/man$(MAN*EXT).

If set to 'none', no man pages will be installed.

=item INSTALLSITESCRIPT

Used by 'make install' which copies files from INST_SCRIPT to this
directory if INSTALLDIRS is set to site (default).

=item INSTALLVENDORARCH

Used by 'make install', which copies files from INST_ARCHLIB to this
directory if INSTALLDIRS is set to vendor. Note that if you do not set
this, the value of INSTALLVENDORLIB will be used, which is probably not
what you want.

=item INSTALLVENDORBIN

Used by 'make install', which copies files from INST_BIN to this
directory if INSTALLDIRS is set to vendor.

=item INSTALLVENDORLIB

Used by 'make install', which copies files from INST_LIB to this
directory if INSTALLDIRS is set to vendor.

=item INSTALLVENDORMAN1DIR

=item INSTALLVENDORMAN3DIR

These directories get the man pages at 'make install' time if
INSTALLDIRS=vendor.  Defaults to $(VENDORPREFIX)/man/man$(MAN*EXT).

If set to 'none', no man pages will be installed.

=item INSTALLVENDORSCRIPT

Available in version 6.30_02 and above.

Used by 'make install' which copies files from INST_SCRIPT to this
directory if INSTALLDIRS is set to vendor.

=item INST_ARCHLIB

Same as INST_LIB for architecture dependent files.

=item INST_BIN

Directory to put real binary files during 'make'. These will be copied
to INSTALLBIN during 'make install'

=item INST_LIB

Directory where we put library files of this extension while building
it.

=item INST_MAN1DIR

Directory to hold the man pages at 'make' time

=item INST_MAN3DIR

Directory to hold the man pages at 'make' time

=item INST_SCRIPT

Directory where executable files should be installed during
'make'. Defaults to "./blib/script", just to have a dummy location during
testing. make install will copy the files in INST_SCRIPT to
INSTALLSCRIPT.

=item LD

Program to be used to link libraries for dynamic loading.

Defaults to $Config{ld}.

=item LDDLFLAGS

Any special flags that might need to be passed to ld to create a
shared library suitable for dynamic loading.  It is up to the makefile
to use it.  (See L<Config/lddlflags>)

Defaults to $Config{lddlflags}.

=item LDFROM

Defaults to "$(OBJECT)" and is used in the ld command to specify
what files to link/load from (also see dynamic_lib below for how to
specify ld flags)

=item LIB

LIB should only be set at C<perl Makefile.PL> time but is allowed as a
MakeMaker argument. It has the effect of setting both INSTALLPRIVLIB
and INSTALLSITELIB to that value regardless any explicit setting of
those arguments (or of PREFIX).  INSTALLARCHLIB and INSTALLSITEARCH
are set to the corresponding architecture subdirectory.

=item LIBPERL_A

The filename of the perllibrary that will be used together with this
extension. Defaults to libperl.a.

=item LIBS

An anonymous array of alternative library
specifications to be searched for (in order) until
at least one library is found. E.g.

  'LIBS' => ["-lgdbm", "-ldbm -lfoo", "-L/path -ldbm.nfs"]

Mind, that any element of the array
contains a complete set of arguments for the ld
command. So do not specify

  'LIBS' => ["-ltcl", "-ltk", "-lX11"]

See ODBM_File/Makefile.PL for an example, where an array is needed. If
you specify a scalar as in

  'LIBS' => "-ltcl -ltk -lX11"

MakeMaker will turn it into an array with one element.

=item LICENSE

Available in version 6.31 and above.

The licensing terms of your distribution.  Generally it's "perl_5" for the
same license as Perl itself.

See L<CPAN::Meta::Spec> for the list of options.

Defaults to "unknown".

=item LINKTYPE

'static' or 'dynamic' (default unless usedl=undef in
config.sh). Should only be used to force static linking (also see
linkext below).

=item MAGICXS

Available in version 6.8305 and above.

When this is set to C<1>, C<OBJECT> will be automagically derived from
C<O_FILES>.

=item MAKE

Available in version 6.30_01 and above.

Variant of make you intend to run the generated Makefile with.  This
parameter lets Makefile.PL know what make quirks to account for when
generating the Makefile.

MakeMaker also honors the MAKE environment variable.  This parameter
takes precedence.

Currently the only significant values are 'dmake' and 'nmake' for Windows
users, instructing MakeMaker to generate a Makefile in the flavour of
DMake ("Dennis Vadura's Make") or Microsoft NMake respectively.

Defaults to $Config{make}, which may go looking for a Make program
in your environment.

How are you supposed to know what flavour of Make a Makefile has
been generated for if you didn't specify a value explicitly? Search
the generated Makefile for the definition of the MAKE variable,
which is used to recursively invoke the Make utility. That will tell
you what Make you're supposed to invoke the Makefile with.

=item MAKEAPERL

Boolean which tells MakeMaker that it should include the rules to
make a perl. This is handled automatically as a switch by
MakeMaker. The user normally does not need it.

=item MAKEFILE_OLD

When 'make clean' or similar is run, the $(FIRST_MAKEFILE) will be
backed up at this location.

Defaults to $(FIRST_MAKEFILE).old or $(FIRST_MAKEFILE)_old on VMS.

=item MAN1PODS

Hashref of pod-containing files. MakeMaker will default this to all
EXE_FILES files that include POD directives. The files listed
here will be converted to man pages and installed as was requested
at Configure time.

This hash should map POD files (or scripts containing POD) to the
man file names under the C<blib/man1/> directory, as in the following
example:

  MAN1PODS            => {
    'doc/command.pod'    => 'blib/man1/command.1',
    'scripts/script.pl'  => 'blib/man1/script.1',
  }

=item MAN3PODS

Hashref that assigns to *.pm and *.pod files the files into which the
manpages are to be written. MakeMaker parses all *.pod and *.pm files
for POD directives. Files that contain POD will be the default keys of
the MAN3PODS hashref. These will then be converted to man pages during
C<make> and will be installed during C<make install>.

Example similar to MAN1PODS.

=item MAP_TARGET

If it is intended that a new perl binary be produced, this variable
may hold a name for that binary. Defaults to perl

=item META_ADD

=item META_MERGE

Available in version 6.46 and above.

A hashref of items to add to the CPAN Meta file (F<META.yml> or
F<META.json>).

They differ in how they behave if they have the same key as the
default metadata.  META_ADD will override the default value with its
own.  META_MERGE will merge its value with the default.

Unless you want to override the defaults, prefer META_MERGE so as to
get the advantage of any future defaults.

Where prereqs are concerned, if META_MERGE is used, prerequisites are merged
with their counterpart C<WriteMakefile()> argument
(PREREQ_PM is merged into {prereqs}{runtime}{requires},
BUILD_REQUIRES into C<{prereqs}{build}{requires}>,
CONFIGURE_REQUIRES into C<{prereqs}{configure}{requires}>,
and TEST_REQUIRES into C<{prereqs}{test}{requires})>.
When prereqs are specified with META_ADD, the only prerequisites added to the
file come from the metadata, not C<WriteMakefile()> arguments.

Note that these configuration options are only used for generating F<META.yml>
and F<META.json> -- they are NOT used for F<MYMETA.yml> and F<MYMETA.json>.
Therefore data in these fields should NOT be used for dynamic (user-side)
configuration.

By default CPAN Meta specification C<1.4> is used. In order to use
CPAN Meta specification C<2.0>, indicate with C<meta-spec> the version
you want to use.

  META_MERGE        => {

    "meta-spec" => { version => 2 },

    resources => {

      repository => {
          type => 'git',
          url => 'git://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker.git',
          web => 'https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker',
      },

    },

  },

=item MIN_PERL_VERSION

Available in version 6.48 and above.

The minimum required version of Perl for this distribution.

Either the 5.006001 or the 5.6.1 format is acceptable.

=item MYEXTLIB

If the extension links to a library that it builds, set this to the
name of the library (see SDBM_File)

=item NAME

The package representing the distribution. For example, C<Test::More>
or C<ExtUtils::MakeMaker>. It will be used to derive information about
the distribution such as the L</DISTNAME>, installation locations
within the Perl library and where XS files will be looked for by
default (see L</XS>).

C<NAME> I<must> be a valid Perl package name and it I<must> have an
associated C<.pm> file. For example, C<Foo::Bar> is a valid C<NAME>
and there must exist F<Foo/Bar.pm>.  Any XS code should be in
F<Bar.xs> unless stated otherwise.

Your distribution B<must> have a C<NAME>.

=item NEEDS_LINKING

MakeMaker will figure out if an extension contains linkable code
anywhere down the directory tree, and will set this variable
accordingly, but you can speed it up a very little bit if you define
this boolean variable yourself.

=item NOECHO

Command so make does not print the literal commands it's running.

By setting it to an empty string you can generate a Makefile that
prints all commands. Mainly used in debugging MakeMaker itself.

Defaults to C<@>.

=item NORECURS

Boolean.  Attribute to inhibit descending into subdirectories.

=item NO_META

When true, suppresses the generation and addition to the MANIFEST of
the META.yml and META.json module meta-data files during 'make distdir'.

Defaults to false.

=item NO_MYMETA

Available in version 6.57_02 and above.

When true, suppresses the generation of MYMETA.yml and MYMETA.json module
meta-data files during 'perl Makefile.PL'.

Defaults to false.

=item NO_PACKLIST

Available in version 6.7501 and above.

When true, suppresses the writing of C<packlist> files for installs.

Defaults to false.

=item NO_PERLLOCAL

Available in version 6.7501 and above.

When true, suppresses the appending of installations to C<perllocal>.

Defaults to false.

=item NO_VC

In general, any generated Makefile checks for the current version of
MakeMaker and the version the Makefile was built under. If NO_VC is
set, the version check is neglected. Do not write this into your
Makefile.PL, use it interactively instead.

=item OBJECT

List of object files, defaults to '$(BASEEXT)$(OBJ_EXT)', but can be a long
string or an array containing all object files, e.g. "tkpBind.o
tkpButton.o tkpCanvas.o" or ["tkpBind.o", "tkpButton.o", "tkpCanvas.o"]

(Where BASEEXT is the last component of NAME, and OBJ_EXT is $Config{obj_ext}.)

=item OPTIMIZE

Defaults to C<-O>. Set it to C<-g> to turn debugging on. The flag is
passed to subdirectory makes.

=item PERL

Perl binary for tasks that can be done by miniperl. If it contains
spaces or other shell metacharacters, it needs to be quoted in a way
that protects them, since this value is intended to be inserted in a
shell command line in the Makefile. E.g.:

  # Perl executable lives in "C:/Program Files/Perl/bin"
  # Normally you don't need to set this yourself!
  $ perl Makefile.PL PERL='"C:/Program Files/Perl/bin/perl.exe" -w'

=item PERL_CORE

Set only when MakeMaker is building the extensions of the Perl core
distribution.

=item PERLMAINCC

The call to the program that is able to compile perlmain.c. Defaults
to $(CC).

=item PERL_ARCHLIB

Same as for PERL_LIB, but for architecture dependent files.

Used only when MakeMaker is building the extensions of the Perl core
distribution (because normally $(PERL_ARCHLIB) is automatically in @INC,
and adding it would get in the way of PERL5LIB).

=item PERL_LIB

Directory containing the Perl library to use.

Used only when MakeMaker is building the extensions of the Perl core
distribution (because normally $(PERL_LIB) is automatically in @INC,
and adding it would get in the way of PERL5LIB).

=item PERL_MALLOC_OK

defaults to 0.  Should be set to TRUE if the extension can work with
the memory allocation routines substituted by the Perl malloc() subsystem.
This should be applicable to most extensions with exceptions of those

=over 4

=item *

with bugs in memory allocations which are caught by Perl's malloc();

=item *

which interact with the memory allocator in other ways than via
malloc(), realloc(), free(), calloc(), sbrk() and brk();

=item *

which rely on special alignment which is not provided by Perl's malloc().

=back

B<NOTE.>  Neglecting to set this flag in I<any one> of the loaded extension
nullifies many advantages of Perl's malloc(), such as better usage of
system resources, error detection, memory usage reporting, catchable failure
of memory allocations, etc.

=item PERLPREFIX

Directory under which core modules are to be installed.

Defaults to $Config{installprefixexp}, falling back to
$Config{installprefix}, $Config{prefixexp} or $Config{prefix} should
$Config{installprefixexp} not exist.

Overridden by PREFIX.

=item PERLRUN

Use this instead of $(PERL) when you wish to run perl.  It will set up
extra necessary flags for you.

=item PERLRUNINST

Use this instead of $(PERL) when you wish to run perl to work with
modules.  It will add things like -I$(INST_ARCH) and other necessary
flags so perl can see the modules you're about to install.

=item PERL_SRC

Directory containing the Perl source code (use of this should be
avoided, it may be undefined)

=item PERM_DIR

Available in version 6.51_01 and above.

Desired permission for directories. Defaults to C<755>.

=item PERM_RW

Desired permission for read/writable files. Defaults to C<644>.

=item PERM_RWX

Desired permission for executable files. Defaults to C<755>.

=item PL_FILES

MakeMaker can run programs to generate files for you at build time.
By default any file named *.PL (except Makefile.PL and Build.PL) in
the top level directory will be assumed to be a Perl program and run
passing its own basename in as an argument.  This basename is actually a build
target, and there is an intention, but not a requirement, that the *.PL file
make the file passed to to as an argument. For example...

    perl foo.PL foo

This behavior can be overridden by supplying your own set of files to
search.  PL_FILES accepts a hash ref, the key being the file to run
and the value is passed in as the first argument when the PL file is run.

    PL_FILES => {'bin/foobar.PL' => 'bin/foobar'}

    PL_FILES => {'foo.PL' => 'foo.c'}

Would run bin/foobar.PL like this:

    perl bin/foobar.PL bin/foobar

If multiple files from one program are desired an array ref can be used.

    PL_FILES => {'bin/foobar.PL' => [qw(bin/foobar1 bin/foobar2)]}

In this case the program will be run multiple times using each target file.

    perl bin/foobar.PL bin/foobar1
    perl bin/foobar.PL bin/foobar2

If an output file depends on extra input files beside the script itself,
a hash ref can be used in version 7.36 and above:

    PL_FILES => { 'foo.PL' => {
        'foo.out' => 'foo.in',
        'bar.out' => [qw(bar1.in bar2.in)],
    }

In this case the extra input files will be passed to the program after
the target file:

   perl foo.PL foo.out foo.in
   perl foo.PL bar.out bar1.in bar2.in

PL files are normally run B<after> pm_to_blib and include INST_LIB and
INST_ARCH in their C<@INC>, so the just built modules can be
accessed... unless the PL file is making a module (or anything else in
PM) in which case it is run B<before> pm_to_blib and does not include
INST_LIB and INST_ARCH in its C<@INC>.  This apparently odd behavior
is there for backwards compatibility (and it's somewhat DWIM).  The argument
passed to the .PL is set up as a target to build in the Makefile.  In other
sections such as C<postamble> you can specify a dependency on the
filename/argument that the .PL is supposed (or will have, now that that is
is a dependency) to generate.  Note the file to be generated will still be
generated and the .PL will still run even without an explicit dependency created
by you, since the C<all> target still depends on running all eligible to run.PL
files.

=item PM

Hashref of .pm files and *.pl files to be installed.  e.g.

  {'name_of_file.pm' => '$(INST_LIB)/install_as.pm'}

By default this will include *.pm and *.pl and the files found in
the PMLIBDIRS directories.  Defining PM in the
Makefile.PL will override PMLIBDIRS.

=item PMLIBDIRS

Ref to array of subdirectories containing library files.  Defaults to
[ 'lib', $(BASEEXT) ]. The directories will be scanned and I<any> files
they contain will be installed in the corresponding location in the
library.  A libscan() method can be used to alter the behaviour.
Defining PM in the Makefile.PL will override PMLIBDIRS.

(Where BASEEXT is the last component of NAME.)

=item PM_FILTER

A filter program, in the traditional Unix sense (input from stdin, output
to stdout) that is passed on each .pm file during the build (in the
pm_to_blib() phase).  It is empty by default, meaning no filtering is done.
You could use:

  PM_FILTER => 'perl -ne "print unless /^\\#/"',

to remove all the leading comments on the fly during the build.  In order
to be as portable as possible, please consider using a Perl one-liner
rather than Unix (or other) utilities, as above.  The # is escaped for
the Makefile, since what is going to be generated will then be:

  PM_FILTER = perl -ne "print unless /^\#/"

Without the \ before the #, we'd have the start of a Makefile comment,
and the macro would be incorrectly defined.

You will almost certainly be better off using the C<PL_FILES> system,
instead. See above, or the L<ExtUtils::MakeMaker::FAQ> entry.

=item POLLUTE

Prior to 5.6 various interpreter variables were available without a C<PL_>
prefix, eg. C<PL_undef> was available as C<undef>. As of release 5.6, these
are only defined if the POLLUTE flag is enabled:

  perl Makefile.PL POLLUTE=1

Please inform the module author if this is necessary to successfully install
a module under 5.6 or later.

=item PPM_INSTALL_EXEC

Name of the executable used to run C<PPM_INSTALL_SCRIPT> below. (e.g. perl)

=item PPM_INSTALL_SCRIPT

Name of the script that gets executed by the Perl Package Manager after
the installation of a package.

=item PPM_UNINSTALL_EXEC

Available in version 6.8502 and above.

Name of the executable used to run C<PPM_UNINSTALL_SCRIPT> below. (e.g. perl)

=item PPM_UNINSTALL_SCRIPT

Available in version 6.8502 and above.

Name of the script that gets executed by the Perl Package Manager before
the removal of a package.

=item PREFIX

This overrides all the default install locations.  Man pages,
libraries, scripts, etc...  MakeMaker will try to make an educated
guess about where to place things under the new PREFIX based on your
Config defaults.  Failing that, it will fall back to a structure
which should be sensible for your platform.

If you specify LIB or any INSTALL* variables they will not be affected
by the PREFIX.

=item PREREQ_FATAL

Bool. If this parameter is true, failing to have the required modules
(or the right versions thereof) will be fatal. C<perl Makefile.PL>
will C<die> instead of simply informing the user of the missing dependencies.

It is I<extremely> rare to have to use C<PREREQ_FATAL>. Its use by module
authors is I<strongly discouraged> and should never be used lightly.

For dependencies that are required in order to run C<Makefile.PL>,
see C<CONFIGURE_REQUIRES>.

Module installation tools have ways of resolving unmet dependencies but
to do that they need a F<Makefile>.  Using C<PREREQ_FATAL> breaks this.
That's bad.

Assuming you have good test coverage, your tests should fail with
missing dependencies informing the user more strongly that something
is wrong.  You can write a F<t/00compile.t> test which will simply
check that your code compiles and stop "make test" prematurely if it
doesn't.  See L<Test::More/BAIL_OUT> for more details.


=item PREREQ_PM

A hash of modules that are needed to run your module.  The keys are
the module names ie. Test::More, and the minimum version is the
value. If the required version number is 0 any version will do.
The versions given may be a Perl v-string (see L<version>) or a range
(see L<CPAN::Meta::Requirements>).

This will go into the C<requires> field of your F<META.yml> and the
C<runtime> of the C<prereqs> field of your F<META.json>.

    PREREQ_PM => {
        # Require Test::More at least 0.47
        "Test::More" => "0.47",

        # Require any version of Acme::Buffy
        "Acme::Buffy" => 0,
    }

=item PREREQ_PRINT

Bool.  If this parameter is true, the prerequisites will be printed to
stdout and MakeMaker will exit.  The output format is an evalable hash
ref.

  $PREREQ_PM = {
                 'A::B' => Vers1,
                 'C::D' => Vers2,
                 ...
               };

If a distribution defines a minimal required perl version, this is
added to the output as an additional line of the form:

  $MIN_PERL_VERSION = '5.008001';

If BUILD_REQUIRES is not empty, it will be dumped as $BUILD_REQUIRES hashref.

=item PRINT_PREREQ

RedHatism for C<PREREQ_PRINT>.  The output format is different, though:

    perl(A::B)>=Vers1 perl(C::D)>=Vers2 ...

A minimal required perl version, if present, will look like this:

    perl(perl)>=5.008001

=item SITEPREFIX

Like PERLPREFIX, but only for the site install locations.

Defaults to $Config{siteprefixexp}.  Perls prior to 5.6.0 didn't have
an explicit siteprefix in the Config.  In those cases
$Config{installprefix} will be used.

Overridable by PREFIX

=item SIGN

Available in version 6.18 and above.

When true, perform the generation and addition to the MANIFEST of the
SIGNATURE file in the distdir during 'make distdir', via 'cpansign
-s'.

Note that you need to install the Module::Signature module to
perform this operation.

Defaults to false.

=item SKIP

Arrayref. E.g. [qw(name1 name2)] skip (do not write) sections of the
Makefile. Caution! Do not use the SKIP attribute for the negligible
speedup. It may seriously damage the resulting Makefile. Only use it
if you really need it.

=item TEST_REQUIRES

Available in version 6.64 and above.

A hash of modules that are needed to test your module but not run or
build it.

This will go into the C<build_requires> field of your F<META.yml> and the C<test> of the C<prereqs> field of your F<META.json>.

The format is the same as PREREQ_PM.

=item TYPEMAPS

Ref to array of typemap file names.  Use this when the typemaps are
in some directory other than the current directory or when they are
not named B<typemap>.  The last typemap in the list takes
precedence.  A typemap in the current directory has highest
precedence, even if it isn't listed in TYPEMAPS.  The default system
typemap has lowest precedence.

=item VENDORPREFIX

Like PERLPREFIX, but only for the vendor install locations.

Defaults to $Config{vendorprefixexp}.

Overridable by PREFIX

=item VERBINST

If true, make install will be verbose

=item VERSION

Your version number for distributing the package.  This defaults to
0.1.

=item VERSION_FROM

Instead of specifying the VERSION in the Makefile.PL you can let
MakeMaker parse a file to determine the version number. The parsing
routine requires that the file named by VERSION_FROM contains one
single line to compute the version number. The first line in the file
that contains something like a $VERSION assignment or C<package Name
VERSION> will be used. The following lines will be parsed o.k.:

    # Good
    package Foo::Bar 1.23;                      # 1.23
    $VERSION   = '1.00';                        # 1.00
    *VERSION   = \'1.01';                       # 1.01
    ($VERSION) = q$Revision$ =~ /(\d+)/g;       # The digits in $Revision$
    $FOO::VERSION = '1.10';                     # 1.10
    *FOO::VERSION = \'1.11';                    # 1.11

but these will fail:

    # Bad
    my $VERSION         = '1.01';
    local $VERSION      = '1.02';
    local $FOO::VERSION = '1.30';

(Putting C<my> or C<local> on the preceding line will work o.k.)

"Version strings" are incompatible and should not be used.

    # Bad
    $VERSION = 1.2.3;
    $VERSION = v1.2.3;

L<version> objects are fine.  As of MakeMaker 6.35 version.pm will be
automatically loaded, but you must declare the dependency on version.pm.
For compatibility with older MakeMaker you should load on the same line
as $VERSION is declared.

    # All on one line
    use version; our $VERSION = qv(1.2.3);

The file named in VERSION_FROM is not added as a dependency to
Makefile. This is not really correct, but it would be a major pain
during development to have to rewrite the Makefile for any smallish
change in that file. If you want to make sure that the Makefile
contains the correct VERSION macro after any change of the file, you
would have to do something like

    depend => { Makefile => '$(VERSION_FROM)' }

See attribute C<depend> below.

=item VERSION_SYM

A sanitized VERSION with . replaced by _.  For places where . has
special meaning (some filesystems, RCS labels, etc...)

=item XS

Hashref of .xs files. MakeMaker will default this.  e.g.

  {'name_of_file.xs' => 'name_of_file.c'}

The .c files will automatically be included in the list of files
deleted by a make clean.

=item XSBUILD

Available in version 7.12 and above.

Hashref with options controlling the operation of C<XSMULTI>:

  {
    xs => {
        all => {
            # options applying to all .xs files for this distribution
        },
        'lib/Class/Name/File' => { # specifically for this file
            DEFINE => '-Dfunktastic', # defines for only this file
            INC => "-I$funkyliblocation", # include flags for only this file
            # OBJECT => 'lib/Class/Name/File$(OBJ_EXT)', # default
            LDFROM => "lib/Class/Name/File\$(OBJ_EXT) $otherfile\$(OBJ_EXT)", # what's linked
        },
    },
  }

Note C<xs> is the file-extension. More possibilities may arise in the
future. Note that object names are specified without their XS extension.

C<LDFROM> defaults to the same as C<OBJECT>. C<OBJECT> defaults to,
for C<XSMULTI>, just the XS filename with the extension replaced with
the compiler-specific object-file extension.

The distinction between C<OBJECT> and C<LDFROM>: C<OBJECT> is the make
target, so make will try to build it. However, C<LDFROM> is what will
actually be linked together to make the shared object or static library
(SO/SL), so if you override it, make sure it includes what you want to
make the final SO/SL, almost certainly including the XS basename with
C<$(OBJ_EXT)> appended.

=item XSMULTI

Available in version 7.12 and above.

When this is set to C<1>, multiple XS files may be placed under F<lib/>
next to their corresponding C<*.pm> files (this is essential for compiling
with the correct C<VERSION> values). This feature should be considered
experimental, and details of it may change.

This feature was inspired by, and small portions of code copied from,
L<ExtUtils::MakeMaker::BigHelper>. Hopefully this feature will render
that module mainly obsolete.

=item XSOPT

String of options to pass to xsubpp.  This might include C<-C++> or
C<-extern>.  Do not include typemaps here; the TYPEMAP parameter exists for
that purpose.

=item XSPROTOARG

May be set to C<-prototypes>, C<-noprototypes> or the empty string.  The
empty string is equivalent to the xsubpp default, or C<-noprototypes>.
See the xsubpp documentation for details.  MakeMaker
defaults to the empty string.

=item XS_VERSION

Your version number for the .xs file of this package.  This defaults
to the value of the VERSION attribute.

=back

=head2 Additional lowercase attributes

can be used to pass parameters to the methods which implement that
part of the Makefile.  Parameters are specified as a hash ref but are
passed to the method as a hash.

=over 2

=item clean

  {FILES => "*.xyz foo"}

=item depend

  {ANY_TARGET => ANY_DEPENDENCY, ...}

(ANY_TARGET must not be given a double-colon rule by MakeMaker.)

=item dist

  {TARFLAGS => 'cvfF', COMPRESS => 'gzip', SUFFIX => '.gz',
  SHAR => 'shar -m', DIST_CP => 'ln', ZIP => '/bin/zip',
  ZIPFLAGS => '-rl', DIST_DEFAULT => 'private tardist' }

If you specify COMPRESS, then SUFFIX should also be altered, as it is
needed to tell make the target file of the compression. Setting
DIST_CP to ln can be useful, if you need to preserve the timestamps on
your files. DIST_CP can take the values 'cp', which copies the file,
'ln', which links the file, and 'best' which copies symbolic links and
links the rest. Default is 'best'.

=item dynamic_lib

  {ARMAYBE => 'ar', OTHERLDFLAGS => '...', INST_DYNAMIC_DEP => '...'}

=item linkext

  {LINKTYPE => 'static', 'dynamic' or ''}

NB: Extensions that have nothing but *.pm files had to say

  {LINKTYPE => ''}

with Pre-5.0 MakeMakers. Since version 5.00 of MakeMaker such a line
can be deleted safely. MakeMaker recognizes when there's nothing to
be linked.

=item macro

  {ANY_MACRO => ANY_VALUE, ...}

=item postamble

Anything put here will be passed to
L<MY::postamble()|ExtUtils::MM_Any/postamble (o)> if you have one.

=item realclean

  {FILES => '$(INST_ARCHAUTODIR)/*.xyz'}

=item test

Specify the targets for testing.

  {TESTS => 't/*.t'}

C<RECURSIVE_TEST_FILES> can be used to include all directories
recursively under C<t> that contain C<.t> files. It will be ignored if
you provide your own C<TESTS> attribute, defaults to false.

  {RECURSIVE_TEST_FILES=>1}

This is supported since 6.76

=item tool_autosplit

  {MAXLEN => 8}

=back

=head2 Overriding MakeMaker Methods

If you cannot achieve the desired Makefile behaviour by specifying
attributes you may define private subroutines in the Makefile.PL.
Each subroutine returns the text it wishes to have written to
the Makefile. To override a section of the Makefile you can
either say:

        sub MY::c_o { "new literal text" }

or you can edit the default by saying something like:

        package MY; # so that "SUPER" works right
        sub c_o {
            my $inherited = shift->SUPER::c_o(@_);
            $inherited =~ s/old text/new text/;
            $inherited;
        }

If you are running experiments with embedding perl as a library into
other applications, you might find MakeMaker is not sufficient. You'd
better have a look at L<ExtUtils::Embed> which is a collection of utilities
for embedding.

If you still need a different solution, try to develop another
subroutine that fits your needs and submit the diffs to
C<makemaker@perl.org>

For a complete description of all MakeMaker methods see
L<ExtUtils::MM_Unix>.

Here is a simple example of how to add a new target to the generated
Makefile:

    sub MY::postamble {
        return <<'MAKE_FRAG';
    $(MYEXTLIB): sdbm/Makefile
            cd sdbm && $(MAKE) all

    MAKE_FRAG
    }

=head2 The End Of Cargo Cult Programming

WriteMakefile() now does some basic sanity checks on its parameters to
protect against typos and malformatted values.  This means some things
which happened to work in the past will now throw warnings and
possibly produce internal errors.

Some of the most common mistakes:

=over 2

=item C<< MAN3PODS => ' ' >>

This is commonly used to suppress the creation of man pages.  MAN3PODS
takes a hash ref not a string, but the above worked by accident in old
versions of MakeMaker.

The correct code is C<< MAN3PODS => { } >>.

=back


=head2 Hintsfile support

MakeMaker.pm uses the architecture-specific information from
Config.pm. In addition it evaluates architecture specific hints files
in a C<hints/> directory. The hints files are expected to be named
like their counterparts in C<PERL_SRC/hints>, but with an C<.pl> file
name extension (eg. C<next_3_2.pl>). They are simply C<eval>ed by
MakeMaker within the WriteMakefile() subroutine, and can be used to
execute commands as well as to include special variables. The rules
which hintsfile is chosen are the same as in Configure.

The hintsfile is eval()ed immediately after the arguments given to
WriteMakefile are stuffed into a hash reference $self but before this
reference becomes blessed. So if you want to do the equivalent to
override or create an attribute you would say something like

    $self->{LIBS} = ['-ldbm -lucb -lc'];

=head2 Distribution Support

For authors of extensions MakeMaker provides several Makefile
targets. Most of the support comes from the L<ExtUtils::Manifest> module,
where additional documentation can be found.

=over 4

=item    make distcheck

reports which files are below the build directory but not in the
MANIFEST file and vice versa. (See L<ExtUtils::Manifest/fullcheck> for
details)

=item    make skipcheck

reports which files are skipped due to the entries in the
C<MANIFEST.SKIP> file (See L<ExtUtils::Manifest/skipcheck> for
details)

=item    make distclean

does a realclean first and then the distcheck. Note that this is not
needed to build a new distribution as long as you are sure that the
MANIFEST file is ok.

=item    make veryclean

does a realclean first and then removes backup files such as C<*~>,
C<*.bak>, C<*.old> and C<*.orig>

=item    make manifest

rewrites the MANIFEST file, adding all remaining files found (See
L<ExtUtils::Manifest/mkmanifest> for details)

=item    make distdir

Copies all the files that are in the MANIFEST file to a newly created
directory with the name C<$(DISTNAME)-$(VERSION)>. If that directory
exists, it will be removed first.

Additionally, it will create META.yml and META.json module meta-data file
in the distdir and add this to the distdir's MANIFEST.  You can shut this
behavior off with the NO_META flag.

=item   make disttest

Makes a distdir first, and runs a C<perl Makefile.PL>, a make, and
a make test in that directory.

=item    make tardist

First does a distdir. Then a command $(PREOP) which defaults to a null
command, followed by $(TO_UNIX), which defaults to a null command under
UNIX, and will convert files in distribution directory to UNIX format
otherwise. Next it runs C<tar> on that directory into a tarfile and
deletes the directory. Finishes with a command $(POSTOP) which
defaults to a null command.

=item    make dist

Defaults to $(DIST_DEFAULT) which in turn defaults to tardist.

=item    make uutardist

Runs a tardist first and uuencodes the tarfile.

=item    make shdist

First does a distdir. Then a command $(PREOP) which defaults to a null
command. Next it runs C<shar> on that directory into a sharfile and
deletes the intermediate directory again. Finishes with a command
$(POSTOP) which defaults to a null command.  Note: For shdist to work
properly a C<shar> program that can handle directories is mandatory.

=item    make zipdist

First does a distdir. Then a command $(PREOP) which defaults to a null
command. Runs C<$(ZIP) $(ZIPFLAGS)> on that directory into a
zipfile. Then deletes that directory. Finishes with a command
$(POSTOP) which defaults to a null command.

=item    make ci

Does a $(CI) and a $(RCS_LABEL) on all files in the MANIFEST file.

=back

Customization of the dist targets can be done by specifying a hash
reference to the dist attribute of the WriteMakefile call. The
following parameters are recognized:

    CI           ('ci -u')
    COMPRESS     ('gzip --best')
    POSTOP       ('@ :')
    PREOP        ('@ :')
    TO_UNIX      (depends on the system)
    RCS_LABEL    ('rcs -q -Nv$(VERSION_SYM):')
    SHAR         ('shar')
    SUFFIX       ('.gz')
    TAR          ('tar')
    TARFLAGS     ('cvf')
    ZIP          ('zip')
    ZIPFLAGS     ('-r')

An example:

    WriteMakefile(
        ...other options...
        dist => {
            COMPRESS => "bzip2",
            SUFFIX   => ".bz2"
        }
    );


=head2 Module Meta-Data (META and MYMETA)

Long plaguing users of MakeMaker based modules has been the problem of
getting basic information about the module out of the sources
I<without> running the F<Makefile.PL> and doing a bunch of messy
heuristics on the resulting F<Makefile>.  Over the years, it has become
standard to keep this information in one or more CPAN Meta files
distributed with each distribution.

The original format of CPAN Meta files was L<YAML> and the corresponding
file was called F<META.yml>.  In 2010, version 2 of the L<CPAN::Meta::Spec>
was released, which mandates JSON format for the metadata in order to
overcome certain compatibility issues between YAML serializers and to
avoid breaking older clients unable to handle a new version of the spec.
The L<CPAN::Meta> library is now standard for accessing old and new-style
Meta files.

If L<CPAN::Meta> is installed, MakeMaker will automatically generate
F<META.json> and F<META.yml> files for you and add them to your F<MANIFEST> as
part of the 'distdir' target (and thus the 'dist' target).  This is intended to
seamlessly and rapidly populate CPAN with module meta-data.  If you wish to
shut this feature off, set the C<NO_META> C<WriteMakefile()> flag to true.

At the 2008 QA Hackathon in Oslo, Perl module toolchain maintainers agreed
to use the CPAN Meta format to communicate post-configuration requirements
between toolchain components.  These files, F<MYMETA.json> and F<MYMETA.yml>,
are generated when F<Makefile.PL> generates a F<Makefile> (if L<CPAN::Meta>
is installed).  Clients like L<CPAN> or L<CPANPLUS> will read these
files to see what prerequisites must be fulfilled before building or testing
the distribution.  If you wish to shut this feature off, set the C<NO_MYMETA>
C<WriteMakeFile()> flag to true.

=head2 Disabling an extension

If some events detected in F<Makefile.PL> imply that there is no way
to create the Module, but this is a normal state of things, then you
can create a F<Makefile> which does nothing, but succeeds on all the
"usual" build targets.  To do so, use

    use ExtUtils::MakeMaker qw(WriteEmptyMakefile);
    WriteEmptyMakefile();

instead of WriteMakefile().

This may be useful if other modules expect this module to be I<built>
OK, as opposed to I<work> OK (say, this system-dependent module builds
in a subdirectory of some other distribution, or is listed as a
dependency in a CPAN::Bundle, but the functionality is supported by
different means on the current architecture).

=head2 Other Handy Functions

=over 4

=item prompt

    my $value = prompt($message);
    my $value = prompt($message, $default);

The C<prompt()> function provides an easy way to request user input
used to write a makefile.  It displays the $message as a prompt for
input.  If a $default is provided it will be used as a default.  The
function returns the $value selected by the user.

If C<prompt()> detects that it is not running interactively and there
is nothing on STDIN or if the PERL_MM_USE_DEFAULT environment variable
is set to true, the $default will be used without prompting.  This
prevents automated processes from blocking on user input.

If no $default is provided an empty string will be used instead.

=item os_unsupported

  os_unsupported();
  os_unsupported if $^O eq 'MSWin32';

The C<os_unsupported()> function provides a way to correctly exit your
C<Makefile.PL> before calling C<WriteMakefile>. It is essentially a
C<die> with the message "OS unsupported".

This is supported since 7.26

=back

=head2 Supported versions of Perl

Please note that while this module works on Perl 5.6, it is no longer
being routinely tested on 5.6 - the earliest Perl version being routinely
tested, and expressly supported, is 5.8.1. However, patches to repair
any breakage on 5.6 are still being accepted.

=head1 ENVIRONMENT

=over 4

=item PERL_MM_OPT

Command line options used by C<MakeMaker-E<gt>new()>, and thus by
C<WriteMakefile()>.  The string is split as the shell would, and the result
is processed before any actual command line arguments are processed.

  PERL_MM_OPT='CCFLAGS="-Wl,-rpath -Wl,/foo/bar/lib" LIBS="-lwibble -lwobble"'

=item PERL_MM_USE_DEFAULT

If set to a true value then MakeMaker's prompt function will
always return the default without waiting for user input.

=item PERL_CORE

Same as the PERL_CORE parameter.  The parameter overrides this.

=back

=head1 SEE ALSO

L<Module::Build> is a pure-Perl alternative to MakeMaker which does
not rely on make or any other external utility.  It may be easier to
extend to suit your needs.

L<Module::Build::Tiny> is a minimal pure-Perl alternative to MakeMaker
that follows the Build.PL protocol of Module::Build but without its
complexity and cruft, implementing only the installation of the module
and leaving authoring to L<mbtiny> or other authoring tools.

L<Module::Install> is a (now discouraged) wrapper around MakeMaker which
adds features not normally available.

L<ExtUtils::ModuleMaker> and L<Module::Starter> are both modules to
help you setup your distribution.

L<CPAN::Meta> and L<CPAN::Meta::Spec> explain CPAN Meta files in detail.

L<File::ShareDir::Install> makes it easy to install static, sometimes
also referred to as 'shared' files. L<File::ShareDir> helps accessing
the shared files after installation. L<Test::File::ShareDir> helps when
writing tests to use the shared files both before and after installation.

L<Dist::Zilla> is an authoring tool which allows great customization and
extensibility of the author experience, relying on the existing install
tools like ExtUtils::MakeMaker only for installation.

L<Dist::Milla> is a Dist::Zilla bundle that greatly simplifies common
usage.

L<Minilla> is a minimal authoring tool that does the same things as
Dist::Milla without the overhead of Dist::Zilla.

=head1 AUTHORS

Andy Dougherty C<doughera@lafayette.edu>, Andreas KE<ouml>nig
C<andreas.koenig@mind.de>, Tim Bunce C<timb@cpan.org>.  VMS
support by Charles Bailey C<bailey@newman.upenn.edu>.  OS/2 support
by Ilya Zakharevich C<ilya@math.ohio-state.edu>.

Currently maintained by Michael G Schwern C<schwern@pobox.com>

Send patches and ideas to C<makemaker@perl.org>.

Send bug reports via http://rt.cpan.org/.  Please send your
generated Makefile along with your report.

For more up-to-date information, see L<https://metacpan.org/release/ExtUtils-MakeMaker>.

Repository available at L<https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker>.

=head1 LICENSE

This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>


=cut
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    Choices-is.utf-8: Engin bráðbirgðaskipting, Báðir Merkja-lyklarnir (Win), Hægri Alt lykill (AltGr), Hægri Merkja-lykill (Win), Vinstri Alt, Vinstri Merkja-lykill (Win)
Choices-it.utf-8: Nessuna commutazione temporanea, Entrambi i tasti Windows, Alt destro (AltGr), Tasto Windows destro, Alt sinistro, Tasto Windows sinistro
Choices-ja.utf-8: 一時切り替えなし, 両ロゴキー, 右 Alt (AltGr), 右ロゴキー, 左 Alt, 左ロゴキー
Choices-kab.utf-8: Ulac agezzam akudan, Snat-nni tqeffalin n ulugu, Alt ayeffus (AltGr), Tasarut n ulugu tayeffust, Alt azelmaḍ, Tasarut n ulugu tazelmaḍt
Choices-kk.utf-8: Уақытша ауыстырғыш жоқ, Екі Logo пернесі, Оң жақ Alt (AltGr), Оң жақ Logo пернесі, Сол жақ Alt, Сол жақ Logo пернесі
Choices-km.utf-8: គ្មាន​ការ​បន្ដូរ​បណ្ដោះ​អាសន្ន​ទេ, គ្រាប់ចុច​ Logo ទាំង​ពីរ, Alt (AltGr) ខាង​ស្ដាំ, គ្រាប់ចុច Logo ខាង​ស្ដាំ, គ្រាប់ Alt ខាង​ឆ្វេង, គ្រាប់ Logo ខាង​ឆ្វេង
Choices-kn.utf-8: ತಾತ್ಕಾಲಿಕ ಬದಲಾವಣೆ ಇರುವುದಿಲ್ಲ, ಎರಡೂ ಲೋಗೋ ಕೀಲಿಗಳು, ಬಲ ಆಲ್ಟ್ (AltGr), ಬಲ ಲೋಗೊ ಕೀಲಿ, ಎಡ ಆಲ್ಟ್, ಎಡ ಲೋಗೊ ಕೀಲಿ
Choices-ko.utf-8: 임시 전환 키 없음, 양쪽 로고 키, 오른쪽 Alt (AltGr), 오른쪽 로고 키, 왼쪽 Alt, 왼쪽 로고 키
Choices-ku.utf-8: Guhestina demî tuneye, Herdu bişkokên logo yê, Rast Alt (AlrGr), Bişkoka logo ya rastê, Alt a çepê, Bişkoka logo ya çepê
Choices-lo.utf-8: ບໍ່ມີສະເຕັບຊົ່ວຄາວ, ທັ້ງສອງຄຣີໂລໂກ້, Alt ຂວາ (AltGr), ແປ້ນໂລໂກ້ຂວາ, Alt ຂ້າງຊ້າຍ, ແປ້ນໂລໂກ້ຊ້າຍ
Choices-lt.utf-8: Laikino perjungimo nenumatyti, Abu Logo klavišai, Dešinysis Alt (Lyg3), Dešinysis Logo klavišas, Kairysis Alt, Kairysis Logo klavišas
Choices-lv.utf-8: Bez īslaicīgā slēdža, Abi Logo taustiņi, Labais Alt (AltGr), Labais Logo taustiņš, Kreisais Alt, Kreisais Logo taustiņš
Choices-mk.utf-8: Без привремена промена, Двете лого копчиња, Десен Alt (AltGr), Десното Лого копче, Лев Alt, Левото лого копче
Choices-ml.utf-8: താത്കാലിക സ്വിച്ചില്ല, രണ്ടു് ലോഗോ കീകളും, വലത് ആള്‍ട്ട് (AltGr), വലത് ലോഗോ കീ, ഇടത് ആള്‍ട്ട്, ഇടത് ലോഗോ കീ
Choices-mr.utf-8: तात्पुरता स्विच नाही, दोन्ही लोगो कळी, उजवी Alt (AltGr), उजवी लोगो कळ, डावी Alt, डावी लोगो कळ
Choices-nb.utf-8: Ingen midlertidig skifting, Begge Logo-tastene, Høyre Alt (AltGr), Høyre logotast, Venstre Alt, Venstre logotast
Choices-nl.utf-8: Geen tijdelijke omschakeling, Beide Logotoetsen, Alt-Rechts (AltGr), Logotoets-Rechts, Alt-Links, Logotoets-Links
Choices-nn.utf-8: Ingen mellombels byte, Båe logotastane, Høgre Alt (AltGr), Høgre logotast, Venstre Alt, Venstre logotast
Choices-no.utf-8: Ingen midlertidig skifting, Begge Logo-tastene, Høyre Alt (AltGr), Høyre logotast, Venstre Alt, Venstre logotast
Choices-oc.utf-8: Pas cap de basculament temporari, Las doas tòcas « lògo », Tòca Alt de drecha (AltGr), Tòca « lògo » de drecha, Alt esquèrra, Tòca « lògo » d'esquèrra
Choices-pa.utf-8: ਕੋਈ ਆਰਜ਼ੀ ਸਵਿੱਚ ਨਹੀਂ, ਦੋਵੇਂ ਲੋਗੋ ਸਵਿੱਚ, ਸੱਜਾ Alt (AltGr), ਸੱਜੀ ਲੋਗੋ ਸਵਿੱਚ, ਖੱਬਾ Alt, ਖੱਬੀ ਲੋਗੋ ਸਵਿੱਚ
Choices-pl.utf-8: Bez tymczasowego przełączania, Oba klawisze logo, Prawy Alt (AltGr), Prawy klawisz logo, Lewy Alt, Lewy klawisz logo
Choices-pt.utf-8: Sem alternância temporária, Ambas as teclas de Logotipo, Alt direito (AltGr), Tecla Logotipo Direito, Alt Esquerdo, Tecla de Logotipo Esquerdo
Choices-pt_br.utf-8: Sem alternador temporário, Ambas teclas Logo, Alt Direito (AltGr), Tecla Logo Direita, Alt Esquerdo, Tecla Logo Esquerda
Choices-ro.utf-8: Fără comutator temporar, Ambele taste Logo, Alt dreapta (AltGr), Tasta logo dreapta, Alt stânga, Tasta logo stânga
Choices-ru.utf-8: нет временного переключателя, обе клавиши с логотипом, правый Alt (AltGr), правая клавиша с логотипом, левый Alt, левая клавиша с логотипом
Choices-si.utf-8: කිසිඳු තාවකාලික ස්විචයක් නොමැත, ලෝගෝ යතුරු දෙකම, දකුණු Alt (AltGr), දකුණු ලාංඡය යතුර, වම් Alt, වම් ලාංඡන යතුර
Choices-sk.utf-8: Žiaden dočasný prepínač, Oba klávesy Logo, Pravý Alt (AltGr), Pravý kláves Logo, Ľavý Alt, Ľavý kláves Logo
Choices-sl.utf-8: Brez začasnega preklopa, Obe tipki z znakom, Desna izmenjalka (AltGR), Desna tipka z znakom, Leva izmenjalka (Alt), Leva tipka z znakom
Choices-sq.utf-8: Nuk ka kalim të përkohshëm, Të dy çelësat Logo, Alt e djathtë (AltGr), Logo key i djathtë, Alt e Majtë, Logo key i Majtë
Choices-sr.utf-8: Без привременог пребацивања, Оба лого тастера, Десни Alt (AltGr), Десни лого тастер, Леви Alt, Леви лого тастер
Choices-sr@latin.utf-8: Bez privremenog prebacivanja, Oba logo tastera, Desni Alt (AltGr), Desni logo taster, Levi Alt, Levi logo taster
Choices-sv.utf-8: Avaktivera temporärt byte, Båda tangenterna med logotype, Alt\, höger (AltGr), Tangent med logotyp\, höger, Alt\, vänster, Tangent med logotyp\, vänster
Choices-ta.utf-8: தற்காலிக மாற்றி இல்லை, இரண்டு லோகோ விசைகளும், வலது ஆல்ட் (AltGr), வலது லோகோ விசை, இடது ஆல்ட், இடது லோகோ விசை
Choices-te.utf-8: తాత్కాలిక  మార్పు లేదు, రెండు బొమ్మ(లోగో) కీలు, కుడి ఆల్ట్ (AltGr), కుడి బొమ్మ కీ, ఎడమ ఆల్ట్, ఎడమ బొమ్మ కీ
Choices-tg.utf-8: Васлкунаки муваққатӣ нест, Ҳар дуи тугмаи тамға, Alt-и рост (AltGr), Тугмаи рости тамға, Alt-и чап, Тугмаи чапи тамға
Choices-th.utf-8: ไม่มีการสลับชั่วคราว, ปุ่มโลโก้คู่, Alt ขวา (AltGr), ปุ่มโลโก้ขวา, Alt ซ้าย, ปุ่มโลโก้ซ้าย
Choices-tr.utf-8: Geçici geçiş yok, Her iki Logo tuşu, Sağ Alt (AltGr), Sağ Logo tuşu, Sol Alt, Sol Logo tuşu
Choices-ug.utf-8: ۋاقىتلىق ئۈزچات يوق, ئىككى Logo كۇنۇپكىسى, ئوڭ Alt (AltGr), ئوڭ  Logo كۇنۇپكا, سول Alt, سول Logo كۇنۇپكا
Choices-uk.utf-8: Без тимчасового перемикача, Обидві клавіші Logo, Правий Alt (AltGr), Права клавіша Logo, Лівий Alt, Ліва клавіша Logo
Choices-vi.utf-8: Không có phím chuyển tạm thời, Cả hai khóa Logo, Alt phải (AltGr), Phím Win phải, Alt trái, Phím Win trái
Choices-zh_cn.utf-8: 无临时切换键, 两个徽标键, 右 Alt 键 (AltGr), 右徽标键, 左 Alt, 左徽标键
Choices-zh_tw.utf-8: 不要暫時切換, 兩邊的 Logo 鍵, 左 Alt (AltGr), 右 Logo 鍵, 左 Alt, 左 Logo 鍵
Default: No temporary switch
Description: Method for temporarily toggling between national and Latin input:
Description-ar.utf-8: طريقة التبديل المؤقت بين الإدخال المحلّي واللاتيني:
Description-ast.utf-8: Métodu pa camudar temporalmente ente nacional y entrada Latina:
Description-be.utf-8: Спосаб часовага пераключэння паміж нацыянальным і лацінскім уводам:
Description-bg.utf-8: Метод за временна смяна между режими „латиница“ и „национални букви“:
Description-bn.utf-8: ন্যাশনাল ও ল্যাটিন ইনপুটের টগল এর অস্থায়ী নিয়ম:
Description-bo.utf-8: གནས་སྐབས་ཀྱི་རང་རྒྱལ་ལུགས་དང་ལ་ཐིན་ཡིག་འཇུག་བར་བརྗེ་རེས་ཀྱི་ཐབས་ཤེས：
Description-bs.utf-8: Metod za privremeno prebacivanje između nacionalnog i Latinskog rasporeda:
Description-ca.utf-8: Mètode per a commutar temporalment entre l'entrada nacional i llatina:
Description-cs.utf-8: Způsob pro dočasné přepnutí mezi vstupem národních znaků a latinkou:
Description-cy.utf-8: Modd i newid dros dro rhwng mewnbwn cenedlaethol a Lladin:
Description-da.utf-8: Metode til midlertidigt at skifte mellem national og latinsk indtastning:
Description-de.utf-8: Methode zum vorübergehenden Wechseln zwischen nationaler und lateinischer Eingabe:
Description-dz.utf-8: རྒྱལ་ཡོངས་དང་ལེ་ཊིན་ཨིན་པུཊི་གཉིས་ཀྱི་བར་ན་ གནས་སྐབས་སོར་སྟོར་གྱི་ཐབས་ལམ།
Description-el.utf-8: Μέθοδος για προσωρινή εναλλαγή μεταξύ εθνικής και λατινικής εισόδου:
Description-eo.utf-8: Metodo por provizore alterni inter nacia kaj Latina enigado:
Description-es.utf-8: Método para cambiar temporalmente entre la entrada nacional y la latina:
Description-et.utf-8: Rahvusliku ja ladina-paigutuse vahel lülitumise viis:
Description-eu.utf-8: Latin eta nazio sarreren artean aldi baterako txandakatzeko metodoa:
Description-fa.utf-8: روشی موقتی برای جابجایی بین حالت بومی و لاتین ورودی:
Description-fi.utf-8: Tapa paikallisen ja Latin-merkistön välillä vaihtamiseen:
Description-fr.utf-8: Méthode de basculement temporaire entre caractères nationaux et latins :
Description-ga.utf-8: Modh scoránaithe idir ionchur náisiúnta agus ionchur Laidineach:
Description-gl.utf-8: Método para conmutar temporalmente entre a entrada nacional e Latin:
Description-gu.utf-8: રાષ્ટ્રિય અને લેટિન ઇનપુટ વચ્ચે બદલાવાની કામચલાઉ રીત:
Description-he.utf-8: שיטה להחלפה זמנית בין קלט מקומי לבין קלט לטיני:
Description-hi.utf-8: इस समय स्थानीय एवं लैटिन अक्षरों के बीच में बदलने का क्रम:
Description-hr.utf-8: Način za privremenu promjenu između nacionalnog i latinskog unosa:
Description-hu.utf-8: A nemzeti és a latin bevitel közötti átmeneti váltás módja:
Description-id.utf-8: Metode untuk berpindah sementara antara masukan nasional dan Latin:
Description-is.utf-8: Aðferð til að skipta til bráðabirgða á milli staðbundins inntaks og þess latneska:
Description-it.utf-8: Metodo per commutare temporaneamente fra input nazionale e latino:
Description-ja.utf-8: ナショナル/ラテン入力で一時切り替えを行う方法:
Description-kab.utf-8: Tarrayt i ubeddel akudan gar yinekcumen aɣelnaw d ulatini:
Description-kk.utf-8: Ұлттық пен латын енгізу режимдері арасында уақытша ауысу тәсілі:
Description-km.utf-8: វិធីសាស្ត្រ​សម្រាប់​បិទ/បើក​បណ្ដោះអាសន្ន​រវាង​កា​របញ្ចូល​ភាសា​ជាតិ និង​ឡាតាំង ៖
Description-kn.utf-8: ತಾತ್ಕಾಲಿಕವಾಗಿ ರಾಷ್ಟ್ರೀಯ ಹಾಗು ಲ್ಯಾಟಿನ್ ಇನ್ಪುಟ್ಗಳ ನಡುವೆ ಅದಲು ಬದಲು ಮಾಡುವ ವಿಧಾನ:
Description-ko.utf-8: 임시로 지역 키보드 입력과 영문 키보드 입력 사이를 토글할 때 사용할 방법:
Description-ku.utf-8: Metoda guherandina di navbera klavyeya neteweyî û Latîn de:
Description-lo.utf-8: ວິທີການຊົ່ວຄາວສັບປ່ຽນລະຫວ່າງອິນພຸດແຫ່ງຊາດແລະພາສາລາຕິນ:
Description-lt.utf-8: Laikino perjungimo tarp nacionalinio ir lotyniško išdėstymo būdas:
Description-lv.utf-8: Īslaicīgi pārslēgt start nacionālo un latīņu režīmu:
Description-mk.utf-8: Метод за привремена промена меѓу национален и латиничен режим:
Description-ml.utf-8: ദേശീയ ഇന്‍പുട്ടും ലാറ്റിന്‍ ഇന്‍പുട്ടും തമ്മില്‍ മാറുന്നതിനുള്ള രീതി
Description-mr.utf-8: राष्ट्रीय व लॅटीन आदान पद्धतीदरम्यान तात्पुरत्या अदलाबदलीसाठीची पद्धत:
Description-nb.utf-8: Metode for å skifte midlertidig mellom nasjonal- og Latin-modus:
Description-nl.utf-8: Methode om tijdelijk te schakelen tussen nationale en Latijnse invoer:
Description-nn.utf-8: Metode for å byte mellombels mellom nasjonal- og latin-modus:
Description-no.utf-8: Metode for å skifte midlertidig mellom nasjonal- og Latin-modus:
Description-oc.utf-8: Metòde de basculament temporari entre caractèrs nacionals e latins :
Description-pa.utf-8: ਰਾਸ਼ਟਰੀ ਲੇਆਉਟ ਤੇ ਸਟੈਂਡਰਡ ਲਾਤੀਨੀ ਇੰਪੁੱਟ ਵਿੱਚ ਬਦਲਣ ਦਾ ਤਰੀਕਾ:
Description-pl.utf-8: Metoda tymczasowego przełączania pomiędzy trybem narodowym i łacińskim:
Description-pt.utf-8: Método para alternar temporariamente entre teclado nacional e Latin:
Description-pt_br.utf-8: Método para alternância temporária entre as entradas nacional e Latin:
Description-ro.utf-8: Metodă pentru comutarea temporară între introducerea în mod național sau latin:
Description-ru.utf-8: Временный переключатель между национальной или латинской раскладкой:
Description-si.utf-8: ජාතික හා ලතින් ආදාන අතර තාවකාලිකව මාරුවීමට ක්‍රමයක්:
Description-sk.utf-8: Spôsob dočasného prepnutia medzi zadávaním národných znakov a Latin:
Description-sl.utf-8: Način začasnega preklopa med narodnim vnosom in vnosom Latin:
Description-sq.utf-8: Metoda për kalimin e përkohshëm midis inputit kombëtar dhe atij Latin
Description-sr.utf-8: Метод за привремено пребацивање између националног и латиничног мода:
Description-sr@latin.utf-8: Metod za privremeno prebacivanje između nacionalnog i latiničnog moda:
Description-sv.utf-8: För att temporärt byta mellan inställningen för nationell och latin-inmatning:
Description-ta.utf-8: தேசிய இட அமைவு மற்றும் இலத்தீன் இட அமைவுகளுக்கு இடையே தற்காலிக நிலை மாற்றுதல்:
Description-te.utf-8: జాతీయ మరియు లాటిన్ మధ్య  తాత్కాలికంగా మారుటకు పద్దతి:
Description-tg.utf-8: Усул барои фаъолсозии муваққатӣ байни вуруди лотинӣ ва миллӣ:
Description-th.utf-8: วิธีสลับภาษาแป้นพิมพ์ระหว่างภาษาท้องถิ่นกับอังกฤษแบบชั่วคราว:
Description-tr.utf-8: Ulusal ve Latin kipler arasında geçici geçiş için kullanılacak yöntem:
Description-ug.utf-8: لاتىنچە بىلەن خەلقئارا كىرگۈزگۈچ ئارىسىدا ۋاقىتلىق ئالماشتۇرۇش ئۇسۇلى:
Description-uk.utf-8: Метод тимчасового перемикання між вводом національних та латинських символів:
Description-vi.utf-8: Phương pháp bật/tắt tạm thời giữa cách gõ quốc gia và La-tinh:
Description-zh_cn.utf-8: 临时在国家和拉丁输入之间切换的方法：
Description-zh_tw.utf-8: 在 national 及 Latin 模式間暫時切換的方式:
Extended_description: When the keyboard is in national mode and one wants to type only a few Latin letters, it might be more appropriate to switch temporarily to Latin mode. The keyboard remains in that mode as long as the chosen key is kept pressed. That key may also be used to input national letters when the keyboard is in Latin mode.\n\nYou can disable this feature by choosing "No temporary switch".
Extended_description-ar.utf-8: عندما تكون لوحة المفاتيح في الوضع المحلّي وتريد أن تكتب بعض الحروف اللاتينية فقط، فقد يكون من الأفضل التبديل مؤقتاً إلى الوضع اللاتيني. وتبقى لوحة المفاتيح بذلك الوضع طالما أن المفتاح المحدد مضغوط. يمكن استخدام ذلك المفتاح أيضاً لإدخال الحروف المحليّة عندما تكون لوحة المفاتيح في الوضع اللاتيني.\n\nيمكنك تعطيل هذه الميزة باختيار "دون تبديل مؤقت".
Extended_description-ast.utf-8: Cuando'l tecláu ta en mou nacional y quies una triba de sólo unos pocos caráuteres llatinos, ye más afayadizo camudar temporalmente a mou Llatín. El tecláu permanez nel mou mientres se caltién primida la tecla esbillada. La tecla puede usase pa introducir les lletres nacionales cuando'l tecláu ta en mou Llatín.\n\nPues desactivar esta opción escoyendo "Nun camudar temporalmente".
Extended_description-be.utf-8: Часам клавіятура ў нацыянальным рэжыме і вы хочаце набраць некалькі лацінскіх літар. Тады будзе зручным часовае пераключэнне ў лацінскі рэжым. Клавіятура знаходзіцца ў ім, пакуль вызначаная кнопка націснутая. Гэтая кнопка таксама можа быць ужыта, каб уводзіць нацыянальныя сімвалы, калі клавіятура ў лацінскім рэжыме.\n\nВы можаце адключыць гэту магчымасць, выбраўшы "Без часовага пераключэння".
Extended_description-bg.utf-8: Когато клавиатурата се намира в режим за национални знаци и искате да въведете само няколко латински букви, може да се окаже удобно да преминете временно в режим „Латиница“.  Клавиатурата остава в този режим дотогава, до когато избраният клавиш се държи натиснат.  Същият клавиш може да се използва и за въвеждане на националните букви, докато клавиатурата се намире в режим „Латиница“.\n\nМоже да забраните тази възможност като изберете варианта „Без временно превключване“.
Extended_description-bn.utf-8: যখন কীবোর্ড ন্যাশনাল মোডে আর একজন শুধু কিছু ল্যাটিন অক্ষর লিখতে চায়, তখন অস্থায়ী ভাবে ল্যাটিন মোডে যওয়াইpackage ExtUtils::ParseXS;
use strict;

use 5.006001;
use Cwd;
use Config;
use Exporter 'import';
use File::Basename;
use File::Spec;
use Symbol;

our $VERSION;
BEGIN {
  $VERSION = '3.45';
  require ExtUtils::ParseXS::Constants; ExtUtils::ParseXS::Constants->VERSION($VERSION);
  require ExtUtils::ParseXS::CountLines; ExtUtils::ParseXS::CountLines->VERSION($VERSION);
  require ExtUtils::ParseXS::Utilities; ExtUtils::ParseXS::Utilities->VERSION($VERSION);
  require ExtUtils::ParseXS::Eval; ExtUtils::ParseXS::Eval->VERSION($VERSION);
}
$VERSION = eval $VERSION if $VERSION =~ /_/;

use ExtUtils::ParseXS::Utilities qw(
  standard_typemap_locations
  trim_whitespace
  C_string
  valid_proto_string
  process_typemaps
  map_type
  standard_XS_defs
  assign_func_args
  analyze_preprocessor_statements
  set_cond
  Warn
  current_line_number
  blurt
  death
  check_conditional_preprocessor_statements
  escape_file_for_line_directive
  report_typemap_failure
);

our @EXPORT_OK = qw(
  process_file
  report_error_count
  errors
);

##############################
# A number of "constants"

our ($C_group_rex, $C_arg);
# Group in C (no support for comments or literals)
$C_group_rex = qr/ [({\[]
             (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )*
             [)}\]] /x;
# Chunk in C without comma at toplevel (no comments):
$C_arg = qr/ (?: (?> [^()\[\]{},"']+ )
       |   (??{ $C_group_rex })
       |   " (?: (?> [^\\"]+ )
         |   \\.
         )* "        # String literal
              |   ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal
       )* /xs;

# "impossible" keyword (multiple newline)
my $END = "!End!\n\n";
# Match an XS Keyword
my $BLOCK_regexp = '\s*(' . $ExtUtils::ParseXS::Constants::XSKeywordsAlternation . "|$END)\\s*:";



sub new {
  return bless {} => shift;
}

our $Singleton = __PACKAGE__->new;

sub process_file {
  my $self;
  # Allow for $package->process_file(%hash), $obj->process_file, and process_file()
  if (@_ % 2) {
    my $invocant = shift;
    $self = ref($invocant) ? $invocant : $invocant->new;
  }
  else {
    $self = $Singleton;
  }

  my %options = @_;
  $self->{ProtoUsed} = exists $options{prototypes};

  # Set defaults.
  my %args = (
    argtypes        => 1,
    csuffix         => '.c',
    except          => 0,
    hiertype        => 0,
    inout           => 1,
    linenumbers     => 1,
    optimize        => 1,
    output          => \*STDOUT,
    prototypes      => 0,
    typemap         => [],
    versioncheck    => 1,
    FH              => Symbol::gensym(),
    %options,
  );
  $args{except} = $args{except} ? ' TRY' : '';

  # Global Constants

  my ($Is_VMS, $SymSet);
  if ($^O eq 'VMS') {
    $Is_VMS = 1;
    # Establish set of global symbols with max length 28, since xsubpp
    # will later add the 'XS_' prefix.
    require ExtUtils::XSSymSet;
    $SymSet = ExtUtils::XSSymSet->new(28);
  }
  @{ $self->{XSStack} } = ({type => 'none'});
  $self->{InitFileCode} = [ @ExtUtils::ParseXS::Constants::InitFileCode ];
  $self->{Overloaded}   = {}; # hashref of Package => Packid
  $self->{Fallback}     = {}; # hashref of Package => fallback setting
  $self->{errors}       = 0; # count

  # Most of the 1500 lines below uses these globals.  We'll have to
  # clean this up sometime, probably.  For now, we just pull them out
  # of %args.  -Ken

  $self->{RetainCplusplusHierarchicalTypes} = $args{hiertype};
  $self->{WantPrototypes} = $args{prototypes};
  $self->{WantVersionChk} = $args{versioncheck};
  $self->{WantLineNumbers} = $args{linenumbers};
  $self->{IncludedFiles} = {};

  die "Missing required parameter 'filename'" unless $args{filename};
  $self->{filepathname} = $args{filename};
  ($self->{dir}, $self->{filename}) =
    (dirname($args{filename}), basename($args{filename}));
  $self->{filepathname} =~ s/\\/\\\\/g;
  $self->{IncludedFiles}->{$args{filename}}++;

  # Open the output file if given as a string.  If they provide some
  # other kind of reference, trust them that we can print to it.
  if (not ref $args{output}) {
    open my($fh), "> $args{output}" or die "Can't create $args{output}: $!";
    $args{outfile} = $args{output};
    $args{output} = $fh;
  }

  # Really, we shouldn't have to chdir() or select() in the first
  # place.  For now, just save and restore.
  my $orig_cwd = cwd();
  my $orig_fh = select();

  chdir($self->{dir});
  my $pwd = cwd();
  my $csuffix = $args{csuffix};

  if ($self->{WantLineNumbers}) {
    my $cfile;
    if ( $args{outfile} ) {
      $cfile = $args{outfile};
    }
    else {
      $cfile = $args{filename};
      $cfile =~ s/\.xs$/$csuffix/i or $cfile .= $csuffix;
    }
    tie(*PSEUDO_STDOUT, 'ExtUtils::ParseXS::CountLines', $cfile, $args{output});
    select PSEUDO_STDOUT;
  }
  else {
    select $args{output};
  }

  $self->{typemap} = process_typemaps( $args{typemap}, $pwd );

  # Move more settings from parameters to object
  foreach my $datum ( qw| argtypes except inout optimize | ) {
    $self->{$datum} = $args{$datum};
  }
  $self->{strip_c_func_prefix} = $args{s};

  # Identify the version of xsubpp used
  print <<EOM;
/*
 * This file was generated automatically by ExtUtils::ParseXS version $VERSION from the
 * contents of $self->{filename}. Do not edit this file, edit $self->{filename} instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

EOM


  print("#line 1 \"" . escape_file_for_line_directive($self->{filepathname}) . "\"\n")
    if $self->{WantLineNumbers};

  # Open the input file (using $self->{filename} which
  # is a basename'd $args{filename} due to chdir above)
  open($self->{FH}, '<', $self->{filename}) or die "cannot open $self->{filename}: $!\n";

  FIRSTMODULE:
  while (readline($self->{FH})) {
    if (/^=/) {
      my $podstartline = $.;
      do {
        if (/^=cut\s*$/) {
          # We can't just write out a /* */ comment, as our embedded
          # POD might itself be in a comment. We can't put a /**/
          # comment inside #if 0, as the C standard says that the source
          # file is decomposed into preprocessing characters in the stage
          # before preprocessing commands are executed.
          # I don't want to leave the text as barewords, because the spec
          # isn't clear whether macros are expanded before or after
          # preprocessing commands are executed, and someone pathological
          # may just have defined one of the 3 words as a macro that does
          # something strange. Multiline strings are illegal in C, so
          # the "" we write must be a string literal. And they aren't
          # concatenated until 2 steps later, so we are safe.
          #     - Nicholas Clark
          print("#if 0\n  \"Skipped embedded POD.\"\n#endif\n");
          printf("#line %d \"%s\"\n", $. + 1, escape_file_for_line_directive($self->{filepathname}))
            if $self->{WantLineNumbers};
          next FIRSTMODULE;
        }

      } while (readline($self->{FH}));
      # At this point $. is at end of file so die won't state the start
      # of the problem, and as we haven't yet read any lines &death won't
      # show the correct line in the message either.
      die ("Error: Unterminated pod in $self->{filename}, line $podstartline\n")
        unless $self->{lastline};
    }
    last if ($self->{Package}, $self->{Prefix}) =
      /^MODULE\s*=\s*[\w:]+(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;

    print $_;
  }
  unless (defined $_) {
    warn "Didn't find a 'MODULE ... PACKAGE ... PREFIX' line\n";
    exit 0; # Not a fatal error for the caller process
  }

  print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};

  standard_XS_defs();

  print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};

  $self->{lastline}    = $_;
  $self->{lastline_no} = $.;

  my $BootCode_ref = [];
  my $XSS_work_idx = 0;
  my $cpp_next_tmp = 'XSubPPtmpAAAA';
 PARAGRAPH:
  while ($self->fetch_para()) {
    my $outlist_ref  = [];
    # Print initial preprocessor statements and blank lines
    while (@{ $self->{line} } && $self->{line}->[0] !~ /^[^\#]/) {
      my $ln = shift(@{ $self->{line} });
      print $ln, "\n";
      next unless $ln =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/;
      my $statement = $+;
      ( $self, $XSS_work_idx, $BootCode_ref ) =
        analyze_preprocessor_statements(
          $self, $statement, $XSS_work_idx, $BootCode_ref
        );
    }

    next PARAGRAPH unless @{ $self->{line} };

    if ($XSS_work_idx && !$self->{XSStack}->[$XSS_work_idx]{varname}) {
      # We are inside an #if, but have not yet #defined its xsubpp variable.
      print "#define $cpp_next_tmp 1\n\n";
      push(@{ $self->{InitFileCode} }, "#if $cpp_next_tmp\n");
      push(@{ $BootCode_ref },     "#if $cpp_next_tmp");
      $self->{XSStack}->[$XSS_work_idx]{varname} = $cpp_next_tmp++;
    }

    $self->death(
      "Code is not inside a function"
        ." (maybe last function was ended by a blank line "
        ." followed by a statement on column one?)")
      if $self->{line}->[0] =~ /^\s/;

    # initialize info arrays
    foreach my $member (qw(args_match var_types defaults arg_list
                           argtype_seen in_out lengthof))
    {
      $self->{$member} = {};
    }
    $self->{proto_arg} = [];
    $self->{processing_arg_with_types} = 0; # bool
    $self->{proto_in_this_xsub}        = 0; # counter & bool
    $self->{scope_in_this_xsub}        = 0; # counter & bool
    $self->{interface}                 = 0; # bool
    $self->{interface_macro}           = 'XSINTERFACE_FUNC';
    $self->{interface_macro_set}       = 'XSINTERFACE_FUNC_SET';
    $self->{ProtoThisXSUB}             = $self->{WantPrototypes}; # states 0 (none), 1 (yes), 2 (empty prototype)
    $self->{ScopeThisXSUB}             = 0; # bool
    $self->{OverloadsThisXSUB}         = {}; # overloaded operators (as hash keys, to de-dup)

    my $xsreturn = 0;

    $_ = shift(@{ $self->{line} });
    while (my $kwd = $self->check_keyword("REQUIRE|PROTOTYPES|EXPORT_XSUB_SYMBOLS|FALLBACK|VERSIONCHECK|INCLUDE(?:_COMMAND)?|SCOPE")) {
      my $method = $kwd . "_handler";
      $self->$method($_);
      next PARAGRAPH unless @{ $self->{line} };
      $_ = shift(@{ $self->{line} });
    }

    if ($self->check_keyword("BOOT")) {
      check_conditional_preprocessor_statements($self);
      push (@{ $BootCode_ref }, "#line $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} }] \""
                                . escape_file_for_line_directive($self->{filepathname}) . "\"")
        if $self->{WantLineNumbers} && $self->{line}->[0] !~ /^\s*#\s*line\b/;
      push (@{ $BootCode_ref }, @{ $self->{line} }, "");
      next PARAGRAPH;
    }

    # extract return type, function name and arguments
    ($self->{ret_type}) = ExtUtils::Typemaps::tidy_type($_);
    my $RETVAL_no_return = 1 if $self->{ret_type} =~ s/^NO_OUTPUT\s+//;

    # Allow one-line ANSI-like declaration
    unshift @{ $self->{line} }, $2
      if $self->{argtypes}
        and $self->{ret_type} =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s;

    # a function definition needs at least 2 lines
    $self->blurt("Error: Function definition too short '$self->{ret_type}'"), next PARAGRAPH
      unless @{ $self->{line} };

    my $externC = 1 if $self->{ret_type} =~ s/^extern "C"\s+//;
    my $static  = 1 if $self->{ret_type} =~ s/^static\s+//;

    my $func_header = shift(@{ $self->{line} });
    $self->blurt("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
      unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*(;\s*)?$/s;

    my ($class, $orig_args);
    ($class, $self->{func_name}, $orig_args) =  ($1, $2, $3);
    $class = "$4 $class" if $4;
    ($self->{pname} = $self->{func_name}) =~ s/^($self->{Prefix})?/$self->{Packprefix}/;
    my $clean_func_name;
    ($clean_func_name = $self->{func_name}) =~ s/^$self->{Prefix}//;
    $self->{Full_func_name} = "$self->{Packid}_$clean_func_name";
    if ($Is_VMS) {
      $self->{Full_func_name} = $SymSet->addsym( $self->{Full_func_name} );
    }

    # Check for duplicate function definition
    for my $tmp (@{ $self->{XSStack} }) {
      next unless defined $tmp->{functions}{ $self->{Full_func_name} };
      Warn( $self, "Warning: duplicate function definition '$clean_func_name' detected");
      last;
    }
    $self->{XSStack}->[$XSS_work_idx]{functions}{ $self->{Full_func_name} }++;
    delete $self->{XsubAliases};
    delete $self->{XsubAliasValues};
    %{ $self->{Interfaces} }      = ();
    @{ $self->{Attributes} }      = ();
    $self->{DoSetMagic} = 1;

    $orig_args =~ s/\\\s*/ /g;    # process line continuations
    my @args;

    my (@fake_INPUT_pre);    # For length(s) generated variables
    my (@fake_INPUT);
    my $only_C_inlist_ref = {};        # Not in the signature of Perl function
    if ($self->{argtypes} and $orig_args =~ /\S/) {
      my $args = "$orig_args ,";
      use re 'eval';
      if ($args =~ /^( (??{ $C_arg }) , )* $ /x) {
        @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg);
        no re 'eval';
        for ( @args ) {
          s/^\s+//;
          s/\s+$//;
          my ($arg, $default) = ($_ =~ m/ ( [^=]* ) ( (?: = .* )? ) /x);
          my ($pre, $len_name) = ($arg =~ /(.*?) \s*
                             \b ( \w+ | length\( \s*\w+\s* \) )
                             \s* $ /x);
          next unless defined($pre) && length($pre);
          my $out_type = '';
          my $inout_var;
          if ($self->{inout} and s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//) {
            my $type = $1;
            $out_type = $type if $type ne 'IN';
            $arg =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//;
            $pre =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//;
          }
          my $islength;
          if ($len_name =~ /^length\( \s* (\w+) \s* \)\z/x) {
            $len_name = "XSauto_length_of_$1";
            $islength = 1;
            die "Default value on length() argument: '$_'"
              if length $default;
          }
          if (length $pre or $islength) { # Has a type
            if ($islength) {
              push @fake_INPUT_pre, $arg;
            }
            else {
              push @fake_INPUT, $arg;
            }
            # warn "pushing '$arg'\n";
            $self->{argtype_seen}->{$len_name}++;
            $_ = "$len_name$default"; # Assigns to @args
          }
          $only_C_inlist_ref->{$_} = 1 if $out_type eq "OUTLIST" or $islength;
          push @{ $outlist_ref }, $len_name if $out_type =~ /OUTLIST$/;
          $self->{in_out}->{$len_name} = $out_type if $out_type;
        }
      }
      else {
        no re 'eval';
        @args = split(/\s*,\s*/, $orig_args);
        Warn( $self, "Warning: cannot parse argument list '$orig_args', fallback to split");
      }
    }
    else {
      @args = split(/\s*,\s*/, $orig_args);
      for (@args) {
        if ($self->{inout} and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\b\s*//) {
          my $out_type = $1;
          next if $out_type eq 'IN';
          $only_C_inlist_ref->{$_} = 1 if $out_type eq "OUTLIST";
          if ($out_type =~ /OUTLIST$/) {
              push @{ $outlist_ref }, undef;
          }
          $self->{in_out}->{$_} = $out_type;
        }
      }
    }
    if (defined($class)) {
      my $arg0 = ((defined($static) or $self->{func_name} eq 'new')
          ? "CLASS" : "THIS");
      unshift(@args, $arg0);
    }
    my $extra_args = 0;
    my @args_num = ();
    my $num_args = 0;
    my $report_args = '';
    my $ellipsis;
    foreach my $i (0 .. $#args) {
      if ($args[$i] =~ s/\.\.\.//) {
        $ellipsis = 1;
        if ($args[$i] eq '' && $i == $#args) {
          $report_args .= ", ...";
          pop(@args);
          last;
        }
      }
      if ($only_C_inlist_ref->{$args[$i]}) {
        push @args_num, undef;
      }
      else {
        push @args_num, ++$num_args;
          $report_args .= ", $args[$i]";
      }
      if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
        $extra_args++;
        $args[$i] = $1;
        $self->{defaults}->{$args[$i]} = $2;
        $self->{defaults}->{$args[$i]} =~ s/"/\\"/g;
      }
      $self->{proto_arg}->[$i+1] = '$' unless $only_C_inlist_ref->{$args[$i]};
    }
    my $min_args = $num_args - $extra_args;
    $report_args =~ s/"/\\"/g;
    $report_args =~ s/^,\s+//;
    $self->{func_args} = assign_func_args($self, \@args, $class);
    @{ $self->{args_match} }{@args} = @args_num;

    my $PPCODE = grep(/^\s*PPCODE\s*:/, @{ $self->{line} });
    my $CODE = grep(/^\s*CODE\s*:/, @{ $self->{line} });
    # Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
    # to set explicit return values.
    my $EXPLICIT_RETURN = ($CODE &&
            ("@{ $self->{line} }" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));

    $self->{ALIAS}  = grep(/^\s*ALIAS\s*:/,  @{ $self->{line} });

    my $INTERFACE  = grep(/^\s*INTERFACE\s*:/,  @{ $self->{line} });

    $xsreturn = 1 if $EXPLICIT_RETURN;

    $externC = $externC ? qq[extern "C"] : "";

    # print function header
    print Q(<<"EOF");
#$externC
#XS_EUPXS(XS_$self->{Full_func_name}); /* prototype to pass -Wmissing-prototypes */
#XS_EUPXS(XS_$self->{Full_func_name})
#[[
#    dVAR; dXSARGS;
EOF
    print Q(<<"EOF") if $self->{ALIAS};
#    dXSI32;
EOF
    print Q(<<"EOF") if $INTERFACE;
#    dXSFUNCTION($self->{ret_type});
EOF

    $self->{cond} = set_cond($ellipsis, $min_args, $num_args);

    print Q(<<"EOF") if $self->{except};
#    char errbuf[1024];
#    *errbuf = '\\0';
EOF

    if($self->{cond}) {
      print Q(<<"EOF");
#    if ($self->{cond})
#       croak_xs_usage(cv,  "$report_args");
EOF
    }
    else {
    # cv and items likely to be unused
    print Q(<<"EOF");
#    PERL_UNUSED_VAR(cv); /* -W */
#    PERL_UNUSED_VAR(items); /* -W */
EOF
    }

    #gcc -Wall: if an xsub has PPCODE is used
    #it is possible none of ST, XSRETURN or XSprePUSH macros are used
    #hence 'ax' (setup by dXSARGS) is unused
    #XXX: could breakup the dXSARGS; into dSP;dMARK;dITEMS
    #but such a move could break third-party extensions
    print Q(<<"EOF") if $PPCODE;
#    PERL_UNUSED_VAR(ax); /* -Wall */
EOF

    print Q(<<"EOF") if $PPCODE;
#    SP -= items;
EOF

    # Now do a block of some sort.

    $self->{condnum} = 0;
    $self->{cond} = '';            # last CASE: conditional
    push(@{ $self->{line} }, "$END:");
    push(@{ $self->{line_no} }, $self->{line_no}->[-1]);
    $_ = '';
    check_conditional_preprocessor_statements();
    while (@{ $self->{line} }) {

      $self->CASE_handler($_) if $self->check_keyword("CASE");
      print Q(<<"EOF");
#   $self->{except} [[
EOF

      # do initialization of input variables
      $self->{thisdone} = 0;
      $self->{retvaldone} = 0;
      $self->{deferred} = "";
      %{ $self->{arg_list} } = ();
      $self->{gotRETVAL} = 0;
      $self->INPUT_handler($_);
      $self->process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD");

      print Q(<<"EOF") if $self->{ScopeThisXSUB};
#   ENTER;
#   [[
EOF

      if (!$self->{thisdone} && defined($class)) {
        if (defined($static) or $self->{func_name} eq 'new') {
          print "\tchar *";
          $self->{var_types}->{"CLASS"} = "char *";
          $self->generate_init( {
            type          => "char *",
            num           => 1,
            var           => "CLASS",
            printed_name  => undef,
          } );
        }
        else {
          print "\t" . map_type($self, "$class *");
          $self->{var_types}->{"THIS"} = "$class *";
          $self->generate_init( {
            type          => "$class *",
            num           => 1,
            var           => "THIS",
            printed_name  => undef,
          } );
        }
      }

      # These are set if OUTPUT is found and/or CODE using RETVAL
      $self->{have_OUTPUT} = $self->{have_CODE_with_RETVAL} = 0;

      my ($wantRETVAL);
      # do code
      if (/^\s*NOT_IMPLEMENTED_YET/) {
        print "\n\tPerl_croak(aTHX_ \"$self->{pname}: not implemented yet\");\n";
        $_ = '';
      }
      else {
        if ($self->{ret_type} ne "void") {
          print "\t" . map_type($self, $self->{ret_type}, 'RETVAL') . ";\n"
            if !$self->{retvaldone};
          $self->{args_match}->{"RETVAL"} = 0;
          $self->{var_types}->{"RETVAL"} = $self->{ret_type};
          my $outputmap = $self->{typemap}->get_outputmap( ctype => $self->{ret_type} );
          print "\tdXSTARG;\n"
            if $self->{optimize} and $outputmap and $outputmap->targetable;
        }

        if (@fake_INPUT or @fake_INPUT_pre) {
          unshift @{ $self->{line} }, @fake_INPUT_pre, @fake_INPUT, $_;
          $_ = "";
          $self->{processing_arg_with_types} = 1;
          $self->INPUT_handler($_);
        }
        print $self->{deferred};

        $self->process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD");

        if ($self->check_keyword("PPCODE")) {
          $self->print_section();
          $self->death("PPCODE must be last thing") if @{ $self->{line} };
          print "\tLEAVE;\n" if $self->{ScopeThisXSUB};
          print "\tPUTBACK;\n\treturn;\n";
        }
        elsif ($self->check_keyword("CODE")) {
          my $consumed_code = $self->print_section();
          if ($consumed_code =~ /\bRETVAL\b/) {
            $self->{have_CODE_with_RETVAL} = 1;
          }
        }
        elsif (defined($class) and $self->{func_name} eq "DESTROY") {
          print "\n\t";
          print "delete THIS;\n";
        }
        else {
          print "\n\t";
          if ($self->{ret_type} ne "void") {
            print "RETVAL = ";
            $wantRETVAL = 1;
          }
          if (defined($static)) {
            if ($self->{func_name} eq 'new') {
              $self->{func_name} = "$class";
            }
            else {
              print "${class}::";
            }
          }
          elsif (defined($class)) {
            if ($self->{func_name} eq 'new') {
              $self->{func_name} .= " $class";
            }
            else {
              print "THIS->";
            }
          }
          my $strip = $self->{strip_c_func_prefix};
          $self->{func_name} =~ s/^\Q$strip//
            if defined $strip;
          $self->{func_name} = 'XSFUNCTION' if $self->{interface};
          print "$self->{func_name}($self->{func_args});\n";
        }
      }

      # do output variables
      $self->{gotRETVAL} = 0;        # 1 if RETVAL seen in OUTPUT section;
      undef $self->{RETVAL_code} ;    # code to set RETVAL (from OUTPUT section);
      # $wantRETVAL set if 'RETVAL =' autogenerated
      ($wantRETVAL, $self->{ret_type}) = (0, 'void') if $RETVAL_no_return;
      undef %{ $self->{outargs} };

      $self->process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");

      # A CODE section with RETVAL, but no OUTPUT? FAIL!
      if ($self->{have_CODE_with_RETVAL} and not $self->{have_OUTPUT} and $self->{ret_type} ne 'void') {
        $self->Warn("Warning: Found a 'CODE' section which seems to be using 'RETVAL' but no 'OUTPUT' section.");
      }

      $self->generate_output( {
        type        => $self->{var_types}->{$_},
        num         => $self->{args_match}->{$_},
        var         => $_,
        do_setmagic => $self->{DoSetMagic},
        do_push     => undef,
      } ) for grep $self->{in_out}->{$_} =~ /OUT$/, sort keys %{ $self->{in_out} };

      my $outlist_count = @{ $outlist_ref };
      if ($outlist_count) {
        my $ext = $outlist_count;
        ++$ext if $self->{gotRETVAL} || $wantRETVAL;
        print "\tXSprePUSH;";
        print "\tEXTEND(SP,$ext);\n";
      }
      # all OUTPUT done, so now push the return value on the stack
      if ($self->{gotRETVAL} && $self->{RETVAL_code}) {
        print "\t$self->{RETVAL_code}\n";
        print "\t++SP;\n" if $outlist_count;
      }
      elsif ($self->{gotRETVAL} || $wantRETVAL) {
        my $outputmap = $self->{typemap}->get_outputmap( ctype => $self->{ret_type} );
        my $trgt = $self->{optimize} && $outputmap && $outputmap->targetable;
        my $var = 'RETVAL';
        my $type = $self->{ret_type};

        if ($trgt) {
          my $what = $self->eval_output_typemap_code(
            qq("$trgt->{what}"),
            {var => $var, type => $self->{ret_type}}
          );
          if (not $trgt->{with_size} and $trgt->{type} eq 'p') { # sv_setpv
            # PUSHp corresponds to sv_setpvn.  Treat sv_setpv directly
              print "\tsv_setpv(TARG, $what);\n";
              print "\tXSprePUSH;\n" unless $outlist_count;
              print "\tPUSHTARG;\n";
          }
          else {
            my $tsize = $trgt->{what_size};
            $tsize = '' unless defined $tsize;
            $tsize = $self->eval_output_typemap_code(
              qq("$tsize"),
              {var => $var, type => $self->{ret_type}}
            );
            print "\tXSprePUSH;\n" unless $outlist_count;
            print "\tPUSH$trgt->{type}($what$tsize);\n";
          }
        }
        else {
          # RETVAL almost never needs SvSETMAGIC()
          $self->generate_output( {
            type        => $self->{ret_type},
            num         => 0,
            var         => 'RETVAL',
            do_setmagic => 0,
            do_push     => undef,
          } );
          print "\t++SP;\n" if $outlist_count;
        }
      }

      $xsreturn = 1 if $self->{ret_type} ne "void";
      my $num = $xsreturn;
      $xsreturn += $outlist_count;
      $self->generate_output( {
        type        => $self->{var_types}->{$_},
        num         => $num++,
        var         => $_,
        do_setmagic => 0,
        do_push     => 1,
      } ) for @{ $outlist_ref };

      # do cleanup
      $self->process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");

      print Q(<<"EOF") if $self->{ScopeThisXSUB};
#   ]]
EOF
      print Q(<<"EOF") if $self->{ScopeThisXSUB} and not $PPCODE;
#   LEAVE;
EOF

      # print function trailer
      print Q(<<"EOF");
#    ]]
EOF
      print Q(<<"EOF") if $self->{except};
#    BEGHANDLERS
#    CATCHALL
#    sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
#    ENDHANDLERS
EOF
      if ($self->check_keyword("CASE")) {
        $self->blurt("Error: No 'CASE:' at top of function")
          unless $self->{condnum};
        $_ = "CASE: $_";    # Restore CASE: label
        next;
      }
      last if $_ eq "$END:";
      $self->death(/^$BLOCK_regexp/o ? "Misplaced '$1:'" : "Junk at end of function ($_)");
    }

    print Q(<<"EOF") if $self->{except};
#    if (errbuf[0])
#    Perl_croak(aTHX_ errbuf);
EOF

    if ($xsreturn) {
      print Q(<<"EOF") unless $PPCODE;
#    XSRETURN($xsreturn);
EOF
    }
    else {
      print Q(<<"EOF") unless $PPCODE;
#    XSRETURN_EMPTY;
EOF
    }

    print Q(<<"EOF");
#]]
#
EOF

    $self->{proto} = "";
    unless($self->{ProtoThisXSUB}) {
      $self->{newXS} = "newXS_deffile";
      $self->{file} = "";
    }
    else {
    # Build the prototype string for the xsub
      $self->{newXS} = "newXSproto_portable";
      $self->{file} = ", file";

      if ($self->{ProtoThisXSUB} eq 2) {
        # User has specified empty prototype
      }
      elsif ($self->{ProtoThisXSUB} eq 1) {
        my $s = ';';
        if ($min_args < $num_args)  {
          $s = '';
          $self->{proto_arg}->[$min_args] .= ";";
        }
        push @{ $self->{proto_arg} }, "$s\@"
          if $ellipsis;

        $self->{proto} = join ("", grep defined, @{ $self->{proto_arg} } );
      }
      else {
        # User has specified a prototype
        $self->{proto} = $self->{ProtoThisXSUB};
      }
      $self->{proto} = qq{, "$self->{proto}"};
    }

    if ($self->{XsubAliases} and keys %{ $self->{XsubAliases} }) {
      $self->{XsubAliases}->{ $self->{pname} } = 0
        unless defined $self->{XsubAliases}->{ $self->{pname} };
      foreach my $xname (sort keys %{ $self->{XsubAliases} }) {
        my $value = $self->{XsubAliases}{$xname};
        push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
#        cv = $self->{newXS}(\"$xname\", XS_$self->{Full_func_name}$self->{file}$self->{proto});
#        XSANY.any_i32 = $value;
EOF
      }
    }
    elsif (@{ $self->{Attributes} }) {
      push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
#        cv = $self->{newXS}(\"$self->{pname}\", XS_$self->{Full_func_name}$self->{file}$self->{proto});
#        apply_attrs_string("$self->{Package}", cv, "@{ $self->{Attributes} }", 0);
EOF
    }
    elsif ($self->{interface}) {
      foreach my $yname (sort keys %{ $self->{Interfaces} }) {
        my $value = $self->{Interfaces}{$yname};
        $yname = "$self->{Package}\::$yname" unless $yname =~ /::/;
        push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
#        cv = $self->{newXS}(\"$yname\", XS_$self->{Full_func_name}$self->{file}$self->{proto});
#        $self->{interface_macro_set}(cv,$value);
EOF
      }
    }
    elsif($self->{newXS} eq 'newXS_deffile'){ # work around P5NCI's empty newXS macro
      push(@{ $self->{InitFileCode} },
       "        $self->{newXS}(\"$self->{pname}\", XS_$self->{Full_func_name}$self->{file}$self->{proto});\n");
    }
    else {
      push(@{ $self->{InitFileCode} },
       "        (void)$self->{newXS}(\"$self->{pname}\", XS_$self->{Full_func_name}$self->{file}$self->{proto});\n");
    }

    for my $operator (keys %{ $self->{OverloadsThisXSUB} }) {
      $self->{Overloaded}->{$self->{Package}} = $self->{Packid};
      my $overload = "$self->{Package}\::($operator";
      push(@{ $self->{InitFileCode} },
        "        (void)$self->{newXS}(\"$overload\", XS_$self->{Full_func_name}$self->{file}$self->{proto});\n");
    }
  } # END 'PARAGRAPH' 'while' loop

  for my $package (keys %{ $self->{Overloaded} }) { # make them findable with fetchmethod
    my $packid = $self->{Overloaded}->{$package};
    print Q(<<"EOF");
#XS_EUPXS(XS_${packid}_nil); /* prototype to pass -Wmissing-prototypes */
#XS_EUPXS(XS_${packid}_nil)
#{
#   dXSARGS;
#   PERL_UNUSED_VAR(items);
#   XSRETURN_EMPTY;
#}
#
EOF
    unshift(@{ $self->{InitFileCode} }, Q(<<"MAKE_FETCHMETHOD_WORK"));
#   /* Making a sub named "${package}::()" allows the package */
#   /* to be findable via fetchmethod(), and causes */
#   /* overload::Overloaded("$package") to return true. */
#   (void)newXS_deffile("${package}::()", XS_${packid}_nil);
MAKE_FETCHMETHOD_WORK
  }

  # print initialization routine

  print Q(<<"EOF");
##ifdef __cplusplus
#extern "C"
##endif
EOF

  print Q(<<"EOF");
#XS_EXTERNAL(boot_$self->{Module_cname}); /* prototype to pass -Wmissing-prototypes */
#XS_EXTERNAL(boot_$self->{Module_cname})
#[[
##if PERL_VERSION_LE(5, 21, 5)
#    dVAR; dXSARGS;
##else
#    dVAR; ${\($self->{WantVersionChk} ?
     'dXSBOOTARGSXSAPIVERCHK;' : 'dXSBOOTARGSAPIVERCHK;')}
##endif
EOF

  #Under 5.8.x and lower, newXS is declared in proto.h as expecting a non-const
  #file name argument. If the wrong qualifier is used, it causes breakage with
  #C++ compilers and warnings with recent gcc.
  #-Wall: if there is no $self->{Full_func_name} there are no xsubs in this .xs
  #so 'file' is unused
  print Q(<<"EOF") if $self->{Full_func_name};
##if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
#    char* file = __FILE__;
##else
#    const char* file = __FILE__;
##endif
#
#    PERL_UNUSED_VAR(file);
EOF

  print Q("#\n");

  print Q(<<"EOF");
#    PERL_UNUSED_VAR(cv); /* -W */
#    PERL_UNUSED_VAR(items); /* -W */
EOF

  if( $self->{WantVersionChk}){
    print Q(<<"EOF") ;
##if PERL_VERSION_LE(5, 21, 5)
#    XS_VERSION_BOOTCHECK;
##  ifdef XS_APIVERSION_BOOTCHECK
#    XS_APIVERSION_BOOTCHECK;
##  endif
##endif

EOF
  } else {
    print Q(<<"EOF") ;
##if PERL_VERSION_LE(5, 21, 5) && defined(XS_APIVERSION_BOOTCHECK)
#  XS_APIVERSION_BOOTCHECK;
##endif

EOF
  }

  print Q(<<"EOF") if defined $self->{XsubAliases} or defined $self->{interfaces};
#    {
#        CV * cv;
#
EOF

  if (%{ $self->{Overloaded} }) {
    # once if any overloads
    print Q(<<"EOF");
#    /* register the overloading (type 'A') magic */
##if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
#    PL_amagic_generation++;
##endif
EOF
    for my $package (keys %{ $self->{Overloaded} }) {
      # once for each package with overloads
      my $fallback = $self->{Fallback}->{$package} || "&PL_sv_undef";
      print Q(<<"EOF");
#    /* The magic for overload gets a GV* via gv_fetchmeth as */
#    /* mentioned above, and looks in the SV* slot of it for */
#    /* the "fallback" status. */
#    sv_setsv(
#        get_sv( "${package}::()", TRUE ),
#        $fallback
#    );
EOF
    }
  }

  print @{ $self->{InitFileCode} };

  print Q(<<"EOF") if defined $self->{XsubAliases} or defined $self->{interfaces};
#    }
EOF

  if (@{ $BootCode_ref }) {
    print "\n    /* Initialisation Section */\n\n";
    @{ $self->{line} } = @{ $BootCode_ref };
    $self->print_section();
    print "\n    /* End of Initialisation Section */\n\n";
  }

  print Q(<<'EOF');
##if PERL_VERSION_LE(5, 21, 5)
##  if PERL_VERSION_GE(5, 9, 0)
#    if (PL_unitcheckav)
#        call_list(PL_scopestack_ix, PL_unitcheckav);
##  endif
#    XSRETURN_YES;
##else
#    Perl_xs_boot_epilog(aTHX_ ax);
##endif
#]]
#
EOF

  warn("Please specify prototyping behavior for $self->{filename} (see perlxs manual)\n")
    unless $self->{ProtoUsed};

  chdir($orig_cwd);
  select($orig_fh);
  untie *PSEUDO_STDOUT if tied *PSEUDO_STDOUT;
  close $self->{FH};

  return 1;
}

sub report_error_count {
  if (@_) {
    return $_[0]->{errors}||0;
  }
  else {
    return $Singleton->{errors}||0;
  }
}
*errors = \&report_error_count;

# Input:  ($self, $_, @{ $self->{line} }) == unparsed input.
# Output: ($_, @{ $self->{line} }) == (rest of line, following lines).
# Return: the matched keyword if found, otherwise 0
sub check_keyword {
  my $self = shift;
  $_ = shift(@{ $self->{line} }) while !/\S/ && @{ $self->{line} };
  s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
}

sub print_section {
  my $self = shift;

  # the "do" is required for right semantics
  do { $_ = shift(@{ $self->{line} }) } while !/\S/ && @{ $self->{line} };

  my $consumed_code = '';

  print("#line ", $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1], " \"",
        escape_file_for_line_directive($self->{filepathname}), "\"\n")
    if $self->{WantLineNumbers} && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/;
  for (;  defined($_) && !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    print "$_\n";
    $consumed_code .= "$_\n";
  }
  print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};

  return $consumed_code;
}

sub merge_section {
  my $self = shift;
  my $in = '';

  while (!/\S/ && @{ $self->{line} }) {
    $_ = shift(@{ $self->{line} });
  }

  for (;  defined($_) && !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    $in .= "$_\n";
  }
  chomp $in;
  return $in;
}

sub process_keyword {
  my($self, $pattern) = @_;

  while (my $kwd = $self->check_keyword($pattern)) {
    my $method = $kwd . "_handler";
    $self->$method($_);
  }
}

sub CASE_handler {
  my $self = shift;
  $_ = shift;
  $self->blurt("Error: 'CASE:' after unconditional 'CASE:'")
    if $self->{condnum} && $self->{cond} eq '';
  $self->{cond} = $_;
  trim_whitespace($self->{cond});
  print "   ", ($self->{condnum}++ ? " else" : ""), ($self->{cond} ? " if ($self->{cond})\n" : "\n");
  $_ = '';
}

sub INPUT_handler {
  my $self = shift;
  $_ = shift;
  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    last if /^\s*NOT_IMPLEMENTED_YET/;
    next unless /\S/;        # skip blank lines

    trim_whitespace($_);
    my $ln = $_;

    # remove trailing semicolon if no initialisation
    s/\s*;$//g unless /[=;+].*\S/;

    # Process the length(foo) declarations
    if (s/^([^=]*)\blength\(\s*(\w+)\s*\)\s*$/$1 XSauto_length_of_$2=NO_INIT/x) {
      print "\tSTRLEN\tSTRLEN_length_of_$2;\n";
      $self->{lengthof}->{$2} = undef;
      $self->{deferred} .= "\n\tXSauto_length_of_$2 = STRLEN_length_of_$2;\n";
    }

    # check for optional initialisation code
    my $var_init = '';
    $var_init = $1 if s/\s*([=;+].*)$//s;
    $var_init =~ s/"/\\"/g;
    # *sigh* It's valid to supply explicit input typemaps in the argument list...
    my $is_overridden_typemap = $var_init =~ /ST\s*\(|\$arg\b/;

    s/\s+/ /g;
    my ($var_type, $var_addr, $var_name) = /^(.*?[^&\s])\s*(\&?)\s*\b(\w+)$/s
      or $self->blurt("Error: invalid argument declaration '$ln'"), next;

    # Check for duplicate definitions
    $self->blurt("Error: duplicate definition of argument '$var_name' ignored"), next
      if $self->{arg_list}->{$var_name}++
        or defined $self->{argtype_seen}->{$var_name} and not $self->{processing_arg_with_types};

    $self->{thisdone} |= $var_name eq "THIS";
    $self->{retvaldone} |= $var_name eq "RETVAL";
    $self->{var_types}->{$var_name} = $var_type;
    # XXXX This check is a safeguard against the unfinished conversion of
    # generate_init().  When generate_init() is fixed,
    # one can use 2-args map_type() unconditionally.
    my $printed_name;
    if ($var_type =~ / \( \s* \* \s* \) /x) {
      # Function pointers are not yet supported with output_init()!
      print "\t" . map_type($self, $var_type, $var_name);
      $printed_name = 1;
    }
    else {
      print "\t" . map_type($self, $var_type, undef);
      $printed_name = 0;
    }
    $self->{var_num} = $self->{args_match}->{$var_name};

    if ($self->{var_num}) {
      my $typemap = $self->{typemap}->get_typemap(ctype => $var_type);
      $self->report_typemap_failure($self->{typemap}, $var_type, "death")
        if not $typemap and not $is_overridden_typemap;
      $self->{proto_arg}->[$self->{var_num}] = ($typemap && $typemap->proto) || "\$";
    }
    $self->{func_args} =~ s/\b($var_name)\b/&$1/ if $var_addr;
    if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/
      or $self->{in_out}->{$var_name} and $self->{in_out}->{$var_name} =~ /^OUT/
      and $var_init !~ /\S/) {
      if ($printed_name) {
        print ";\n";
      }
      else {
        print "\t$var_name;\n";
      }
    }
    elsif ($var_init =~ /\S/) {
      $self->output_init( {
        type          => $var_type,
        num           => $self->{var_num},
        var           => $var_name,
        init          => $var_init,
        printed_name  => $printed_name,
      } );
    }
    elsif ($self->{var_num}) {
      $self->generate_init( {
        type          => $var_type,
        num           => $self->{var_num},
        var           => $var_name,
        printed_name  => $printed_name,
      } );
    }
    else {
      print ";\n";
    }
  }
}

sub OUTPUT_handler {
  my $self = shift;
  $self->{have_OUTPUT} = 1;

  $_ = shift;
  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    next unless /\S/;
    if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) {
      $self->{DoSetMagic} = ($1 eq "ENABLE" ? 1 : 0);
      next;
    }
    my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s;
    $self->blurt("Error: duplicate OUTPUT argument '$outarg' ignored"), next
      if $self->{outargs}->{$outarg}++;
    if (!$self->{gotRETVAL} and $outarg eq 'RETVAL') {
      # deal with RETVAL last
      $self->{RETVAL_code} = $outcode;
      $self->{gotRETVAL} = 1;
      next;
    }
    $self->blurt("Error: OUTPUT $outarg not an argument"), next
      unless defined($self->{args_match}->{$outarg});
    $self->blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
      unless defined $self->{var_types}->{$outarg};
    $self->{var_num} = $self->{args_match}->{$outarg};
    if ($outcode) {
      print "\t$outcode\n";
      print "\tSvSETMAGIC(ST(" , $self->{var_num} - 1 , "));\n" if $self->{DoSetMagic};
    }
    else {
      $self->generate_output( {
        type        => $self->{var_types}->{$outarg},
        num         => $self->{var_num},
        var         => $outarg,
        do_setmagic => $self->{DoSetMagic},
        do_push     => undef,
      } );
    }
    delete $self->{in_out}->{$outarg}     # No need to auto-OUTPUT
      if exists $self->{in_out}->{$outarg} and $self->{in_out}->{$outarg} =~ /OUT$/;
  }
}

sub C_ARGS_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self->merge_section();

  trim_whitespace($in);
  $self->{func_args} = $in;
}

sub INTERFACE_MACRO_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self->merge_section();

  trim_whitespace($in);
  if ($in =~ /\s/) {        # two
    ($self->{interface_macro}, $self->{interface_macro_set}) = split ' ', $in;
  }
  else {
    $self->{interface_macro} = $in;
    $self->{interface_macro_set} = 'UNKNOWN_CVT'; # catch later
  }
  $self->{interface} = 1;        # local
  $self->{interfaces} = 1;        # global
}

sub INTERFACE_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self->merge_section();

  trim_whitespace($in);

  foreach (split /[\s,]+/, $in) {
    my $iface_name = $_;
    $iface_name =~ s/^$self->{Prefix}//;
    $self->{Interfaces}->{$iface_name} = $_;
  }
  print Q(<<"EOF");
#    XSFUNCTION = $self->{interface_macro}($self->{ret_type},cv,XSANY.any_dptr);
EOF
  $self->{interface} = 1;        # local
  $self->{interfaces} = 1;        # global
}

sub CLEANUP_handler {
  my $self = shift;
  $self->print_section();
}

sub PREINIT_handler {
  my $self = shift;
  $self->print_section();
}

sub POSTCALL_handler {
  my $self = shift;
  $self->print_section();
}

sub INIT_handler {
  my $self = shift;
  $self->print_section();
}

sub get_aliases {
  my $self = shift;
  my ($line) = @_;
  my ($orig) = $line;

  # Parse alias definitions
  # format is
  #    alias = value alias = value ...

  while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
    my ($alias, $value) = ($1, $2);
    my $orig_alias = $alias;

    # check for optional package definition in the alias
    $alias = $self->{Packprefix} . $alias if $alias !~ /::/;

    # check for duplicate alias name & duplicate value
    Warn( $self, "Warning: Ignoring duplicate alias '$orig_alias'")
      if defined $self->{XsubAliases}->{$alias};

    Warn( $self, "Warning: Aliases '$orig_alias' and '$self->{XsubAliasValues}->{$value}' have identical values")
      if $self->{XsubAliasValues}->{$value};

    $self->{XsubAliases}->{$alias} = $value;
    $self->{XsubAliasValues}->{$value} = $orig_alias;
  }

  blurt( $self, "Error: Cannot parse ALIAS definitions from '$orig'")
    if $line;
}

sub ATTRS_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    push @{ $self->{Attributes} }, $_;
  }
}

sub ALIAS_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    $self->get_aliases($_) if $_;
  }
}

sub OVERLOAD_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    while ( s/^\s*([\w:"\\)\+\-\*\/\%\<\>\.\&\|\^\!\~\{\}\=]+)\s*//) {
      $self->{OverloadsThisXSUB}->{$1} = 1;
    }
  }
}

sub FALLBACK_handler {
  my ($self, $setting) = @_;

  # the rest of the current line should contain either TRUE,
  # FALSE or UNDEF

  trim_whitespace($setting);
  $setting = uc($setting);

  my %map = (
    TRUE => "&PL_sv_yes", 1 => "&PL_sv_yes",
    FALSE => "&PL_sv_no", 0 => "&PL_sv_no",
    UNDEF => "&PL_sv_undef",
  );

  # check for valid FALLBACK value
  $self->death("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{$setting};

  $self->{Fallback}->{$self->{Package}} = $map{$setting};
}


sub REQUIRE_handler {
  # the rest of the current line should contain a version number
  my ($self, $ver) = @_;

  trim_whitespace($ver);

  $self->death("Error: REQUIRE expects a version number")
    unless $ver;

  # check that the version number is of the form n.n
  $self->death("Error: REQUIRE: expected a number, got '$ver'")
    unless $ver =~ /^\d+(\.\d*)?/;

  $self->death("Error: xsubpp $ver (or better) required--this is only $VERSION.")
    unless $VERSION >= $ver;
}

sub VERSIONCHECK_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self->death("Error: VERSIONCHECK: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  $self->{WantVersionChk} = 1 if $1 eq 'ENABLE';
  $self->{WantVersionChk} = 0 if $1 eq 'DISABLE';

}

sub PROTOTYPE_handler {
  my $self = shift;
  $_ = shift;

  my $specified;

  $self->death("Error: Only 1 PROTOTYPE definition allowed per xsub")
    if $self->{proto_in_this_xsub}++;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self->{line} })) {
    next unless /\S/;
    $specified = 1;
    trim_whitespace($_);
    if ($_ eq 'DISABLE') {
      $self->{ProtoThisXSUB} = 0;
    }
    elsif ($_ eq 'ENABLE') {
      $self->{ProtoThisXSUB} = 1;
    }
    else {
      # remove any whitespace
      s/\s+//g;
      $self->death("Error: Invalid prototype '$_'")
        unless valid_proto_string($_);
      $self->{ProtoThisXSUB} = C_string($_);
    }
  }

  # If no prototype specified, then assume empty prototype ""
  $self->{ProtoThisXSUB} = 2 unless $specified;

  $self->{ProtoUsed} = 1;
}

sub SCOPE_handler {
  # Rest of line should be either ENABLE or DISABLE
  my ($self, $setting) = @_;

  $self->death("Error: Only 1 SCOPE declaration allowed per xsub")
    if $self->{scope_in_this_xsub}++;

  trim_whitespace($setting);
  $self->death("Error: SCOPE: ENABLE/DISABLE")
      unless $setting =~ /^(ENABLE|DISABLE)\b/i;
  $self->{ScopeThisXSUB} = ( uc($1) eq 'ENABLE' );
}

sub PROTOTYPES_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self->death("Error: PROTOTYPES: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  $self->{WantPrototypes} = 1 if $1 eq 'ENABLE';
  $self->{WantPrototypes} = 0 if $1 eq 'DISABLE';
  $self->{ProtoUsed} = 1;
}

sub EXPORT_XSUB_SYMBOLS_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self->death("Error: EXPORT_XSUB_SYMBOLS: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  my $xs_impl = $1 eq 'ENABLE' ? 'XS_EXTERNAL' : 'XS_INTERNAL';

  print Q(<<"EOF");
##undef XS_EUPXS
##if defined(PERL_EUPXS_ALWAYS_EXPORT)
##  define XS_EUPXS(name) XS_EXTERNAL(name)
##elif defined(PERL_EUPXS_NEVER_EXPORT)
##  define XS_EUPXS(name) XS_INTERNAL(name)
##else
##  define XS_EUPXS(name) $xs_impl(name)
##endif
EOF
}


sub PushXSStack {
  my $self = shift;
  my %args = @_;
  # Save the current file context.
  push(@{ $self->{XSStack} }, {
          type            => 'file',
          LastLine        => $self->{lastline},
          LastLineNo      => $self->{lastline_no},
          Line            => $self->{line},
          LineNo          => $self->{line_no},
          Filename        => $self->{filename},
          Filepathname    => $self->{filepathname},
          Handle          => $self->{FH},
          IsPipe          => scalar($self->{filename} =~ /\|\s*$/),
          %args,
         });

}

sub INCLUDE_handler {
  my $self = shift;
  $_ = shift;
  # the rest of the current line should contain a valid filename

  trim_whitespace($_);

  $self->death("INCLUDE: filename missing")
    unless $_;

  $self->death("INCLUDE: output pipe is illegal")
    if /^\s*\|/;

  # simple minded recursion detector
  $self->death("INCLUDE loop detected")
    if $self->{IncludedFiles}->{$_};

  ++$self->{IncludedFiles}->{$_} unless /\|\s*$/;

  if (/\|\s*$/ && /^\s*perl\s/) {
    Warn( $self, "The INCLUDE directive with a command is discouraged." .
          " Use INCLUDE_COMMAND instead! In particular using 'perl'" .
          " in an 'INCLUDE: ... |' directive is not guaranteed to pick" .
          " up the correct perl. The INCLUDE_COMMAND directive allows" .
          " the use of \$^X as the currently running perl, see" .
          " 'perldoc perlxs' for details.");
  }

  $self->PushXSStack();

  $self->{FH} = Symbol::gensym();

  # open the new file
  open($self->{FH}, $_) or $self->death("Cannot open '$_': $!");

  print Q(<<"EOF");
#
#/* INCLUDE:  Including '$_' from '$self->{filename}' */
#
EOF

  $self->{filename} = $_;
  $self->{filepathname} = ( $^O =~ /^mswin/i )
                          ? qq($self->{dir}/$self->{filename}) # See CPAN RT #61908: gcc doesn't like backslashes on win32?
                          : File::Spec->catfile($self->{dir}, $self->{filename});

  # Prime the pump by reading the first
  # non-blank line

  # skip leading blank lines
  while (readline($self->{FH})) {
    last unless /^\s*$/;
  }

  $self->{lastline} = $_;
  $self->{lastline_no} = $.;
}

sub QuoteArgs {
  my $cmd = shift;
  my @args = split /\s+/, $cmd;
  $cmd = shift @args;
  for (@args) {
    $_ = q(").$_.q(") if !/^\"/ && length($_) > 0;
  }
  return join (' ', ($cmd, @args));
}

# code copied from CPAN::HandleConfig::safe_quote
#  - that has doc saying leave if start/finish with same quote, but no code
# given text, will conditionally quote it to protect from shell
{
  my ($quote, $use_quote) = $^O eq 'MSWin32'
      ? (q{"}, q{"})
      : (q{"'}, q{'});
  sub _safe_quote {
      my ($self, $command) = @_;
      # Set up quote/default quote
      if (defined($command)
          and $command =~ /\s/
          and $command !~ /[$quote]/) {
          return qq{$use_quote$command$use_quote}
      }
      return $command;
  }
}

sub INCLUDE_COMMAND_handler {
  my $self = shift;
  $_ = shift;
  # the rest of the current line should contain a valid command

  trim_whitespace($_);

  $_ = QuoteArgs($_) if $^O eq 'VMS';

  $self->death("INCLUDE_COMMAND: command missing")
    unless $_;

  $self->death("INCLUDE_COMMAND: pipes are illegal")
    if /^\s*\|/ or /\|\s*$/;

  $self->PushXSStack( IsPipe => 1 );

  $self->{FH} = Symbol::gensym();

  # If $^X is used in INCLUDE_COMMAND, we know it's supposed to be
  # the same perl interpreter as we're currently running
  my $X = $self->_safe_quote($^X); # quotes if has spaces
  s/^\s*\$\^X/$X/;

  # open the new file
  open ($self->{FH}, "-|", $_)
    or $self->death( $self, "Cannot run command '$_' to include its output: $!");

  print Q(<<"EOF");
#
#/* INCLUDE_COMMAND:  Including output of '$_' from '$self->{filename}' */
#
EOF

  $self->{filename} = $_;
  $self->{filepathname} = $self->{filename};
  #$self->{filepathname} =~ s/\"/\\"/g; # Fails? See CPAN RT #53938: MinGW Broken after 2.21
  $self->{filepathname} =~ s/\\/\\\\/g; # Works according to reporter of #53938

  # Prime the pump by reading the first
  # non-blank line

  # skip leading blank lines
  while (readline($self->{FH})) {
    last unless /^\s*$/;
  }

  $self->{lastline} = $_;
  $self->{lastline_no} = $.;
}

sub PopFile {
  my $self = shift;

  return 0 unless $self->{XSStack}->[-1]{type} eq 'file';

  my $data     = pop @{ $self->{XSStack} };
  my $ThisFile = $self->{filename};
  my $isPipe   = $data->{IsPipe};

  --$self->{IncludedFiles}->{$self->{filename}}
    unless $isPipe;

  close $self->{FH};

  $self->{FH}         = $data->{Handle};
  # $filename is the leafname, which for some reason is used for diagnostic
  # messages, whereas $filepathname is the full pathname, and is used for
  # #line directives.
  $self->{filename}   = $data->{Filename};
  $self->{filepathname} = $data->{Filepathname};
  $self->{lastline}   = $data->{LastLine};
  $self->{lastline_no} = $data->{LastLineNo};
  @{ $self->{line} }       = @{ $data->{Line} };
  @{ $self->{line_no} }    = @{ $data->{LineNo} };

  if ($isPipe and $? ) {
    --$self->{lastline_no};
    print STDERR "Error reading from pipe '$ThisFile': $! in $self->{filename}, line $self->{lastline_no}\n" ;
    exit 1;
  }

  print Q(<<"EOF");
#
#/* INCLUDE: Returning to '$self->{filename}' from '$ThisFile' */
#
EOF

  return 1;
}

sub Q {
  my($text) = @_;
  $text =~ s/^#//gm;
  $text =~ s/\[\[/{/g;
  $text =~ s/\]\]/}/g;
  $text;
}

# Process "MODULE = Foo ..." lines and update global state accordingly
sub _process_module_xs_line {
  my ($self, $module, $pkg, $prefix) = @_;

  ($self->{Module_cname} = $module) =~ s/\W/_/g;

  $self->{Package} = defined($pkg) ? $pkg : '';
  $self->{Prefix}  = quotemeta( defined($prefix) ? $prefix : '' );

  ($self->{Packid} = $self->{Package}) =~ tr/:/_/;

  $self->{Packprefix} = $self->{Package};
  $self->{Packprefix} .= "::" if $self->{Packprefix} ne "";

  $self->{lastline} = "";
}

# Skip any embedded POD sections
sub _maybe_skip_pod {
  my ($self) = @_;

  while ($self->{lastline} =~ /^=/) {
    while ($self->{lastline} = readline($self->{FH})) {
      last if ($self->{lastline} =~ /^=cut\s*$/);
    }
    $self->death("Error: Unterminated pod") unless defined $self->{lastline};
    $self->{lastline} = readline($self->{FH});
    chomp $self->{lastline};
    $self->{lastline} =~ s/^\s+$//;
  }
}

# This chunk of code strips out (and parses) embedded TYPEMAP blocks
# which support a HEREdoc-alike block syntax.
sub _maybe_parse_typemap_block {
  my ($self) = @_;

  # This is special cased from the usual paragraph-handler logic
  # due to the HEREdoc-ish syntax.
  if ($self->{lastline} =~ /^TYPEMAP\s*:\s*<<\s*(?:(["'])(.+?)\1|([^\s'"]+?))\s*;?\s*$/)
  {
    my $end_marker = quotemeta(defined($1) ? $2 : $3);

    # Scan until we find $end_marker alone on a line.
    my @tmaplines;
    while (1) {
      $self->{lastline} = readline($self->{FH});
      $self->death("Error: Unterminated TYPEMAP section") if not defined $self->{lastline};
      last if $self->{lastline} =~ /^$end_marker\s*$/;
      push @tmaplines, $self->{lastline};
    }

    my $tmap = ExtUtils::Typemaps->new(
      string        => join("", @tmaplines),
      lineno_offset => 1 + ($self->current_line_number() || 0),
      fake_filename => $self->{filename},
    );
    $self->{typemap}->merge(typemap => $tmap, replace => 1);

    $self->{lastline} = "";
  }
}

# Read next xsub into @{ $self->{line} } from ($lastline, readline($self->{FH})).
sub fetch_para {
  my $self = shift;

  # parse paragraph
  $self->death("Error: Unterminated '#if/#ifdef/#ifndef'")
    if !defined $self->{lastline} && $self->{XSStack}->[-1]{type} eq 'if';
  @{ $self->{line} } = ();
  @{ $self->{line_no} } = ();
  return $self->PopFile() if not defined $self->{lastline}; # EOF

  if ($self->{lastline} =~
      /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/)
  {
    $self->_process_module_xs_line($1, $2, $3);
  }

  for (;;) {
    $self->_maybe_skip_pod;

    $self->_maybe_parse_typemap_block;

    if ($self->{lastline} !~ /^\s*#/ # not a CPP directive
        # CPP directives:
        #    ANSI:    if ifdef ifndef elif else endif define undef
        #        line error pragma
        #    gcc:    warning include_next
        #   obj-c:    import
        #   others:    ident (gcc notes that some cpps have this one)
        || $self->{lastline} =~ /^\#[ \t]*
                                  (?:
                                        (?:if|ifn?def|elif|else|endif|
                                           define|undef|pragma|error|
                                           warning|line\s+\d+|ident)
                                        \b
                                      | (?:include(?:_next)?|import)
                                        \s* ["<] .* [>"]
                                 )
                                /x
    )
    {
      last if $self->{lastline} =~ /^\S/ && @{ $self->{line} } && $self->{line}->[-1] eq "";
      push(@{ $self->{line} }, $self->{lastline});
      push(@{ $self->{line_no} }, $self->{lastline_no});
    }

    # Read next line and continuation lines
    last unless defined($self->{lastline} = readline($self->{FH}));
    $self->{lastline_no} = $.;
    my $tmp_line;
    $self->{lastline} .= $tmp_line
      while ($self->{lastline} =~ /\\$/ && defined($tmp_line = readline($self->{FH})));

    chomp $self->{lastline};
    $self->{lastline} =~ s/^\s+$//;
  }

  # Nuke trailing "line" entries until there's one that's not empty
  pop(@{ $self->{line} }), pop(@{ $self->{line_no} })
    while @{ $self->{line} } && $self->{line}->[-1] eq "";

  return 1;
}

sub output_init {
  my $self = shift;
  my $argsref = shift;

  my ($type, $num, $var, $init, $printed_name)
    = @{$argsref}{qw(type num var init printed_name)};

  # local assign for efficiently passing in to eval_input_typemap_code
  local $argsref->{arg} = $num
                          ? "ST(" . ($num-1) . ")"
                          : "/* not a parameter */";

  if ( $init =~ /^=/ ) {
    if ($printed_name) {
      $self->eval_input_typemap_code(qq/print " $init\\n"/, $argsref);
    }
    else {
      $self->eval_input_typemap_code(qq/print "\\t$var $init\\n"/, $argsref);
    }
  }
  else {
    if (  $init =~ s/^\+//  &&  $num  ) {
      $self->generate_init( {
        type          => $type,
        num           => $num,
        var           => $var,
        printed_name  => $printed_name,
      } );
    }
    elsif ($printed_name) {
      print ";\n";
      $init =~ s/^;//;
    }
    else {
      $self->eval_input_typemap_code(qq/print "\\t$var;\\n"/, $argsref);
      $init =~ s/^;//;
    }
    $self->{deferred}
      .= $self->eval_input_typemap_code(qq/"\\n\\t$init\\n"/, $argsref);
  }
}

sub generate_init {
  my $self = shift;
  my $argsref = shift;

  my ($type, $num, $var, $printed_name)
    = @{$argsref}{qw(type num var printed_name)};

  my $argoff = $num - 1;
  my $arg = "ST($argoff)";

  my $typemaps = $self->{typemap};

  $type = ExtUtils::Typemaps::tidy_type($type);
  if (not $typemaps->get_typemap(ctype => $type)) {
    $self->report_typemap_failure($typemaps, $type);
    return;
  }

  (my $ntype = $type) =~ s/\s*\*/Ptr/g;
  (my $subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;

  my $typem = $typemaps->get_typemap(ctype => $type);
  my $xstype = $typem->xstype;
  #this is an optimization from perl 5.0 alpha 6, class check is skipped
  #T_REF_IV_REF is missing since it has no untyped analog at the moment
  $xstype =~ s/OBJ$/REF/ || $xstype =~ s/^T_REF_IV_PTR$/T_PTRREF/
    if $self->{func_name} =~ /DESTROY$/;
  if ($xstype eq 'T_PV' and exists $self->{lengthof}->{$var}) {
    print "\t$var" unless $printed_name;
    print " = ($type)SvPV($arg, STRLEN_length_of_$var);\n";
    die "default value not supported with length(NAME) supplied"
      if defined $self->{defaults}->{$var};
    return;
  }
  $type =~ tr/:/_/ unless $self->{RetainCplusplusHierarchicalTypes};

  my $inputmap = $typemaps->get_inputmap(xstype => $xstype);
  if (not defined $inputmap) {
    $self->blurt("Error: No INPUT definition for type '$type', typekind '$xstype' found");
    return;
  }

  my $expr = $inputmap->cleaned_code;
  # Note: This gruesome bit either needs heavy rethinking or documentation. I vote for the former. --Steffen
  if ($expr =~ /DO_ARRAY_ELEM/) {
    my $subtypemap  = $typemaps->get_typemap(ctype => $subtype);
    if (not $subtypemap) {
      $self->report_typemap_failure($typemaps, $subtype);
      return;
    }

    my $subinputmap = $typemaps->get_inputmap(xstype => $subtypemap->xstype);
    if (not $subinputmap) {
      $self->blurt("Error: No INPUT definition for type '$subtype', typekind '" . $subtypemap->xstype . "' found");
      return;
    }

    my $subexpr = $subinputmap->cleaned_code;
    $subexpr =~ s/\$type/\$subtype/g;
    $subexpr =~ s/ntype/subtype/g;
    $subexpr =~ s/\$arg/ST(ix_$var)/g;
    $subexpr =~ s/\n\t/\n\t\t/g;
    $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g;
    $subexpr =~ s/\$var/${var}\[ix_$var - $argoff]/;
    $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
  }
  if ($expr =~ m#/\*.*scope.*\*/#i) {  # "scope" in C comments
    $self->{ScopeThisXSUB} = 1;
  }

  my $eval_vars = {
    var           => $var,
    printed_name  => $printed_name,
    type          => $type,
    ntype         => $ntype,
    subtype       => $subtype,
    num           => $num,
    arg           => $arg,
    argoff        => $argoff,
  };

  if (defined($self->{defaults}->{$var})) {
    $expr =~ s/(\t+)/$1    /g;
    $expr =~ s/        /\t/g;
    if ($printed_name) {
      print ";\n";
    }
    else {
      $self->eval_input_typemap_code(qq/print "\\t$var;\\n"/, $eval_vars);
    }
    if ($self->{defaults}->{$var} eq 'NO_INIT') {
      $self->{deferred} .= $self->eval_input_typemap_code(
        qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/,
        $eval_vars
      );
    }
    else {
      $self->{deferred} .= $self->eval_input_typemap_code(
        qq/"\\n\\tif (items < $num)\\n\\t    $var = $self->{defaults}->{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/,
        $eval_vars
      );
    }
  }
  elsif ($self->{ScopeThisXSUB} or $expr !~ /^\s*\$var =/) {
    if ($printed_name) {
      print ";\n";
    }
    else {
      $self->eval_input_typemap_code(qq/print "\\t$var;\\n"/, $eval_vars);
    }
    $self->{deferred}
      .= $self->eval_input_typemap_code(qq/"\\n$expr;\\n"/, $eval_vars);
  }
  else {
    die "panic: do not know how to handle this branch for function pointers"
      if $printed_name;
    $self->eval_input_typemap_code(qq/print "$expr;\\n"/, $eval_vars);
  }
}

sub generate_output {
  my $self = shift;
  my $argsref = shift;
  my ($type, $num, $var, $do_setmagic, $do_push)
    = @{$argsref}{qw(type num var do_setmagic do_push)};

  my $arg = "ST(" . ($num - ($num != 0)) . ")";

  my $typemaps = $self->{typemap};

  $type = ExtUtils::Typemaps::tidy_type($type);
  local $argsref->{type} = $type;

  if ($type =~ /^array\(([^,]*),(.*)\)/) {
    print "\t$arg = sv_newmortal();\n";
    print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1));\n";
    print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
  }
  else {
    my $typemap = $typemaps->get_typemap(ctype => $type);
    if (not $typemap) {
      $self->report_typemap_failure($typemaps, $type);
      return;
    }

    my $outputmap = $typemaps->get_outputmap(xstype => $typemap->xstype);
    if (not $outputmap) {
      $self->blurt("Error: No OUTPUT definition for type '$type', typekind '" . $typemap->xstype . "' found");
      return;
    }

    (my $ntype = $type) =~ s/\s*\*/Ptr/g;
    $ntype =~ s/\(\)//g;
    (my $subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;

    my $eval_vars = {%$argsref, subtype => $subtype, ntype => $ntype, arg => $arg};
    my $expr = $outputmap->cleaned_code;
    if ($expr =~ /DO_ARRAY_ELEM/) {
      my $subtypemap = $typemaps->get_typemap(ctype => $subtype);
      if (not $subtypemap) {
        $self->report_typemap_failure($typemaps, $subtype);
        return;
      }

      my $suboutputmap = $typemaps->get_outputmap(xstype => $subtypemap->xstype);
      if (not $suboutputmap) {
        $self->blurt("Error: No OUTPUT definition for type '$subtype', typekind '" . $subtypemap->xstype . "' found");
        return;
      }

      my $subexpr = $suboutputmap->cleaned_code;
      $subexpr =~ s/ntype/subtype/g;
      $subexpr =~ s/\$arg/ST(ix_$var)/g;
      $subexpr =~ s/\$var/${var}\[ix_$var]/g;
      $subexpr =~ s/\n\t/\n\t\t/g;
      $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
      $self->eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic;
    }
    elsif ($var eq 'RETVAL') {
      my $orig_arg = $arg;
      my $indent;
      my $use_RETVALSV = 1;
      my $do_mortal = 0;
      my $do_copy_tmp = 1;
      my $pre_expr;
      local $eval_vars->{arg} = $arg = 'RETVALSV';
      my $evalexpr = $self->eval_output_typemap_code("qq\a$expr\a", $eval_vars);

      if ($expr =~ /^\t\Q$arg\E = new/) {
        # We expect that $arg has refcnt 1, so we need to
        # mortalize it.
        $do_mortal = 1;
      }
      # If RETVAL is immortal, don't mortalize it. This code is not perfect:
      # It won't detect a func or expression that only returns immortals, for
      # example, this RE must be tried before next elsif.
      elsif ($evalexpr =~ /^\t\Q$arg\E\s*=\s*(boolSV\(|(&PL_sv_yes|&PL_sv_no|&PL_sv_undef)\s*;)/) {
        $do_copy_tmp = 0; #$arg will be a ST(X), no SV* RETVAL, no RETVALSV
        $use_RETVALSV = 0;
      }
      elsif ($evalexpr =~ /^\s*\Q$arg\E\s*=/) {
        # We expect that $arg has refcnt >=1, so we need
        # to mortalize it!
        $use_RETVALSV = 0 if $ntype eq "SVPtr";#reuse SV* RETVAL vs open new block
        $do_mortal = 1;
      }
      else {
        # Just hope that the entry would safely write it
        # over an already mortalized value. By
        # coincidence, something like $arg = &PL_sv_undef
        # works too, but should be caught above.
        $pre_expr = "RETVALSV = sv_newmortal();\n";
        # new mortals don't have set magic
        $do_setmagic = 0;
      }
      if($use_RETVALSV) {
        print "\t{\n\t    SV * RETVALSV;\n";
        $indent = "\t    ";
      } else {
        $indent = "\t";
      }
      print $indent.$pre_expr if $pre_expr;

      if($use_RETVALSV) {
        #take control of 1 layer of indent, may or may not indent more
        $evalexpr =~ s/^(\t|        )/$indent/gm;
        #"\t    \t" doesn't draw right in some IDEs
        #break down all \t into spaces
        $evalexpr =~ s/\t/        /g;
        #rebuild back into \t'es, \t==8 spaces, indent==4 spaces
        $evalexpr =~ s/        /\t/g;
      }
      else {
        if($do_mortal || $do_setmagic) {
        #typemap entry evaled with RETVALSV, if we aren't using RETVALSV replace
          $evalexpr =~ s/RETVALSV/RETVAL/g; #all uses with RETVAL for prettier code
        }
        else { #if no extra boilerplate (no mortal, no set magic) is needed
            #after $evalexport, get rid of RETVALSV's visual cluter and change
          $evalexpr =~ s/RETVALSV/$orig_arg/g;#the lvalue to ST(X)
        }
      }
      #stop "	RETVAL = RETVAL;" for SVPtr type
      print $evalexpr if $evalexpr !~ /^\s*RETVAL = RETVAL;$/;
      print $indent.'RETVAL'.($use_RETVALSV ? 'SV':'')
            .' = sv_2mortal(RETVAL'.($use_RETVALSV ? 'SV':'').");\n" if $do_mortal;
      print $indent.'SvSETMAGIC(RETVAL'.($use_RETVALSV ? 'SV':'').");\n" if $do_setmagic;
      #dont do "RETVALSV = boolSV(RETVAL); ST(0) = RETVALSV;", it is visual clutter
      print $indent."$orig_arg = RETVAL".($use_RETVALSV ? 'SV':'').";\n"
        if $do_mortal || $do_setmagic || $do_copy_tmp;
      print "\t}\n" if $use_RETVALSV;
    }
    elsif ($do_push) {
      print "\tPUSHs(sv_newmortal());\n";
      local $eval_vars->{arg} = "ST($num)";
      $self->eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
    }
    elsif ($arg =~ /^ST\(\d+\)$/) {
      $self->eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
    }
  }
}


# Just delegates to a clean package.
# Shim to evaluate Perl code in the right variable context
# for typemap code (having things such as $ALIAS set up).
sub eval_output_typemap_code {
  my ($self, $code, $other) = @_;
  return ExtUtils::ParseXS::Eval::eval_output_typemap_code($self, $code, $other);
}

sub eval_input_typemap_code {
  my ($self, $code, $other) = @_;
  return ExtUtils::ParseXS::Eval::eval_input_typemap_code($self, $code, $other);
}

1;

# vim: ts=2 sw=2 et:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ్ట్+కేప్స్ లాక్, ఎడమ కంట్రోల్+ఎడమ షిఫ్ట్, ఎడమ ఆల్ట్, ఎడమ కంట్రోల్, ఎడమ షిఫ్ట్, ఎడమ బొమ్మ కీ, స్క్రాల్ లాక్ కీ, టాగ్లింగ్ లేదు
Choices-tg.utf-8: Caps Lock, Alt-и рост (AltGr), Control-и рост, Shift-и рост, Тугмаи рости тамға, Тугмаи меню, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, Control-и чап+Shift-и чап, Alt-и чап, Control-и чап, Shift-и чап, Тугмаи чапи тамға, Тугмаи Scroll Lock, Бе интихобкунӣ
Choices-th.utf-8: Caps Lock, Alt ขวา (AltGr), Control ขวา, Shift ขวา, ปุ่มโลโก้ขวา, ปุ่มเมนู, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, Control ซ้าย+Shift ซ้าย, Alt ซ้าย, Control ซ้าย, Shift ซ้าย, ปุ่มโลโก้ซ้าย, ปุ่ม Scroll Lock, ไม่มีการสลับ
Choices-tr.utf-8: Caps Lock (Büyük Harf Kilidi), Sağ Alt (AltGr), Sağ Control, Sağ Shift, Sağ Logo tuşu, Menü tuşu, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock (Büyük Harf Kilidi), Sol Control+Sol Shift, Sol Alt, Sol Control, Sol Shift, Sol Logo tuşu, Kaydırma Kilidi (Scroll Lock) tuşu, Kip değiştirme yok
Choices-ug.utf-8: CapsLock, ئوڭ Alt (AltGr), ئوڭ Control, ئوڭ Shift, ئوڭ  Logo كۇنۇپكا, تىزىملىك كۇنۇپكا, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, سول Control + سول Shift, سول Alt, سول Control, سول Shift, سول Logo كۇنۇپكا, Scroll Lock كۇنۇپكا, ئالماشتۇرما
Choices-uk.utf-8: Caps Lock, Правий Alt (AltGr), Правий Control, Правий Shift, Права клавіша Logo, Клавіша Menu, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, Лівий Control+Лівий Shift, Лівий Alt, Лівий Control, Лівий Shift, Ліва клавіша Logo, Клавіша Scroll Lock, Без перемикання
Choices-vi.utf-8: Caps Lock, Alt phải (AltGr), Ctrl phải, Shift phải, Phím Win phải, Phím trình đơn, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, Left trái+Left trái, Alt trái, Ctrl trái, Shift trái, Phím Win trái, Phím Scroll Lock, Không bật/tắt
Choices-zh_cn.utf-8: 大写锁定键, 右 Alt 键 (AltGr), 右 Control 键, 右 Shift 键, 右徽标键, 菜单键, Alt+Shift, Control+Shift, Control+Alt, Alt+大写锁定键, 左 Control+左 Shift, 左 Alt, 左 Control, 左 Shift, 左徽标键, 滚动锁定键, 无切换
Choices-zh_tw.utf-8: Caps Lock, 左 Alt (AltGr), 右 Control, 右 Shift, 右 Logo 鍵, Menu 鍵, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, 左邊的 Control+左邊的 Shift, 左 Alt, 左 Control, 左 Shift, 左 Logo 鍵, Scroll Lock 鍵, 不切換
Default: Alt+Shift
Description: Method for toggling between national and Latin mode:
Description-am.utf-8: በላቲንና በብሔራዊ ሞድ መቀየራ ዘዴ
Description-ar.utf-8: طريقة التبديل بين الوضع المحلي واللاتيني:
Description-ast.utf-8: Métodu p'alternar ente nacional y mou Latinu:
Description-be.utf-8: Спосаб пераключэння між нацыянальным і лацінскім рэжымамі:
Description-bg.utf-8: Метод за превключване между режими „латиница“ и „национални букви“:
Description-bn.utf-8: ন্যাশনাল ও ল্যাটিন মুডে টগল্ এর নিয়ম:
Description-bo.utf-8: རང་རྒྱལ་ལམ་ལ་ཐིན་གྱི་རྣམ་པའི་བར་བརྗེ་རེས་ཀྱི་ཐབས་ཤེས：
Description-bs.utf-8: Metod prebacivanja između nacionalnog i Latinskog moda:
Description-ca.utf-8: Mètode per a commutar entre el mode nacional i llatí:
Description-cs.utf-8: Způsob přepínání mezi vstupem národních znaků a latinkou:
Description-cy.utf-8: Dull o doglo rhwng modd cenedlaethol a Lladin:
Description-da.utf-8: Metode til at skifte mellem national og latinsk tilstand:
Description-de.utf-8: Methode zur Umschaltung zwischen nationalem und lateinischem Modus:
Description-dz.utf-8: རྒྱལ་ཡོངས་དང་ལེ་ཊིན་གནས་ཐངས་བར་ན་སོར་སྟོན་ཐབས་ལམ།
Description-el.utf-8: Μέθοδος εναλλαγής μεταξύ τοπικής και Λατινικής διάταξης πληκτρολογίου:
Description-eo.utf-8: Metodo por baskuli inter nacia kaj latina reĝimo:
Description-es.utf-8: Método para cambiar entre modo nacional y latino:
Description-et.utf-8: Rahvusliku ja ladina paigutuse vahetamine:
Description-eu.utf-8: Latin eta nazio moduen artean txandakatzeko metodoa:
Description-fa.utf-8: روش تغییر وضعیت بین حالت ملّی و لاتین:
Description-fi.utf-8: Tapa paikallisen ja Latin-tilan välillä vaihtamiseen:
Description-fr.utf-8: Méthode de basculement entre le mode national et le mode latin :
Description-ga.utf-8: Modh scoránaithe idir an mód náisiúnta agus an mód Laidineach:
Description-gl.utf-8: Método para conmutar entre o modo nacional e o modo Latin:
Description-gu.utf-8: રાષ્ટ્રિય અને લેટિન સ્થિતિ વચ્ચે બદલાવાની રીત:
Description-he.utf-8: שיטת מעבר בין מצב עבודה לאומי ומצב עבודה לטיני:
Description-hi.utf-8: देशी तथा लैटिन मोड के बीच परिवर्तन हेतु:
Description-hr.utf-8: Način promjene između nacionalnog i latinskog načina:
Description-hu.utf-8: Mód a nemzeti és latin mód közti váltásra:
Description-id.utf-8: Metode untuk berpindah modus nasional dan Latin:
Description-is.utf-8: Aðferð til að víxla á milli staðbundinar uppsetningar og latneskrar:
Description-it.utf-8: Metodo per commutare fra modo nazionale e latino:
Description-ja.utf-8: ナショナル/ラテンモードを切り替える方法:
Description-kab.utf-8: Tarrayt i ubeddel gar uskar alatini aɣelnaw:
Description-kk.utf-8: Ұлттық пен латын режимдері арасында ауысу тәсілі:
Description-km.utf-8: វិធីសាស្ត្រ​សម្រាប់​បិទ/បើក​រវាង​របៀប​ភាសា​ជាតិ និង​ឡាតាំង ៖
Description-kn.utf-8: ರಾಷ್ಟ್ರೀಯ ಹಾಗು ಲ್ಯಾಟಿನ್ ವಿಧಾನಗಳ ನಡುವೆ ಅದಲುಬದಲು ಮಾಡುವ ವಿಧಿ
Description-ko.utf-8: 지역 키보드 입력과 영문 키보드 입력 사이를 토글할 때 사용할 방법:
Description-ku.utf-8: Metoda ji bo guherandina di navbera moda neteweyî û Latîn de:
Description-lo.utf-8: ວິທີການສະຫລັບລະຫວ່າງໂຫມດແຫ່ງຊາດແລະພາສາລາຕິນ
Description-lt.utf-8: Perjungimo tarp nacionalinio ir lotyniško išdėstymų būdas:
Description-lv.utf-8: Pārslēgt starp nacionālo un latīņu režīmu:
Description-mk.utf-8: Метод за промена меѓу национален и латиничен режим:
Description-ml.utf-8: ദേശീയ ലാറ്റിന്‍ ദശകള്‍ തമ്മില്‍ മാറാന്‍ ഉപയോഗിയ്ക്കുന്ന രീതി:
Description-mr.utf-8: नॅशनल व लॅटिन यांदरम्यान टॉगलिंगची पद्धत:
Description-nb.utf-8: Metode for å skifte mellom nasjonal- og Latin-modus:
Description-ne.utf-8: देशी तथा लैटिन मोड के बीच परिवर्तन गर्ने विधि:
Description-nl.utf-8: Methode om te schakelen tussen nationale en Latijnse modus:
Description-nn.utf-8: Metode for å skifte mellom nasjonal- og latin-modus:
Description-no.utf-8: Metode for å skifte mellom nasjonal- og Latin-modus:
Description-oc.utf-8: Metòde de basculament entre lo mòde nacional e lo mòde latin :
Description-pa.utf-8: ਰਾਸ਼ਟਰੀ ਤੇ ਲਾਤੀਨੀ ਮੋਡ ਵਿੱਚ ਬਦਲਣ ਦਾ ਤਰੀਕਾ:
Description-pl.utf-8: Metoda przełączania pomiędzy trybem narodowym i łacińskim:
Description-pt.utf-8: Método para alternar entre o modo nacional e Latin:
Description-pt_br.utf-8: Método para alternância entre modos nacional e Latin:
Description-ro.utf-8: Metoda de comutare între modul național și modul latin:
Description-ru.utf-8: Способ переключения между национальной и латинской раскладкой:
Description-si.utf-8: ජාතික හා ලතින් ප්‍රකාර අතර මාරුවීමේ ක්‍රමය:
Description-sk.utf-8: Spôsob prepínania medzi národným režimom a Latin:
Description-sl.utf-8: Način preklopa med narodnim načinom in Latin:
Description-sq.utf-8: Metoda për toggling mes mënyrës nacionale dhe Latine
Description-sr.utf-8: Метод за пребацивање између националног и латиничног мода:
Description-sr@latin.utf-8: Metod za prebacivanje između nacionalnog i latiničnog moda:
Description-sv.utf-8: Metod att byta mellan inställning för nationellt och latin:
Description-ta.utf-8: தேசிய மற்றும் இலத்தீன் பாங்குகளுக்கு நிலை மாற்றுதல் முறை:
Description-te.utf-8: జాతీయ మరియు లాటిన్ మధ్య మారుటకు పద్దతి:
Description-tg.utf-8: Усули интихобкунии реҷаи миллӣ ва лотинӣ:
Description-th.utf-8: วิธีสลับภาษาท้องถิ่นกับอังกฤษ:
Description-tr.utf-8: Ulusal ve Latin kipler arasında geçiş için kullanılacak yöntem:
Description-ug.utf-8: لاتىنچە بىلەن خەلقئارا كىرگۈزۈش ھالىتىنى ئالماشتۇرۇش ئۇسۇلى:
Description-uk.utf-8: Метод перемикання між національною та латинською розкладкою:
Description-vi.utf-8: Phương pháp bật/tắt giữa chế độ quốc gia và chế độ La-tinh:
Description-zh_cn.utf-8: 用于在国家与拉丁模式之间切换的方法：
Description-zh_tw.utf-8: 在 national 及 Latin 模式間的切換方式:
Extended_description: You will need a way to toggle the keyboard between the national layout and the standard Latin layout.\n\nRight Alt or Caps Lock keys are often chosen for ergonomic reasons (in the latter case, use the combination Shift+Caps Lock for normal Caps toggle). Alt+Shift is also a popular combination; it will however lose its usual behavior in Emacs and other programs that use it for specific needs.\n\nNot all listed keys are present on all keyboards.
Extended_description-am.utf-8: በቁልፍ ገበታው ላይ በብሔራዊና  በላቲን ፊደል አጣጣል መሃከል የመቀየርያ መንገድ ያስፈልጎታል።\n\nየእርግን ቀኝ Alt ወይም Caps Lock ቁልፎች keys በአብዛኛው ለምቾት ሲባል ጥቅም ላይ ይውላሉ። (የኋለኛውን ወደ ተለምዶው ለመቀየር Shift+Capsን ይጠቀሙ). Alt+Shift እንዲሁ ተወዳጅ ቅንብር ነው። ነገርግን በEmacsና ሌሎች በተለየ ሁኔታ የሚጠቀሙበት ስልቶች ልይ የተለምዶ ባህሪውን ያጣል።\n\nሁሉም የተመዘገቡ ቁልፎች በሁሉም  ፊደል ገበታ ላይ አይገኙም
Extended_description-ar.utf-8: ستحتاج إلى طريقة لتبديل لوحة المفاتيح بين التخطيط المحلي والتخطيط اللاتيني القياسي.\n\nزر Alt الأيمن أو Caps Lock عادة تستخدم لأسباب راحة المستخدم (وفي حالة استخدام Caps Lock للتبديل، اضغط Shift+Caps Lock للتبديل بين الحروف الصغيرة والكبيرة). كما يشيع استخدام زرّي Alt+Shift، إلا أنها قد تفقد سلوكها المعتاد في إيماكس وفي البرامج الأخرى التي تستخدمها لأغراض معيّنة.\n\nليست جميع المفاتيح المسردة موجودة في جميع لوحات المفاتيح.
Extended_description-ast.utf-8: Necesites una manera d'alternar el tecláu ente la distribución nacional y la distribución standard Latina.\n\nAlt Derecha o tecla Caps Lock escuéyense normalmente por razones ergonómiques (nel casu caberu, usa la combinación May+Caps Lock p'alternar Caps). Alt+May ye tamién una combinación popular; Sicasí, perderáse'l so comportamientu habitual n'Emacs y otros programes que lo usen pa necesidaes específiques.\n\nNon toles tecles llistaes tán en tolos teclaos.
Extended_description-be.utf-8: Вам трэба вызначыць спосаб пераключэння клавіятуры паміж нацыянальнай і стандартнай лацінскай раскладкай.\n\nНайбольш эрганамічнымі варыянтамі ёсць правы Alt ды Caps Lock (у апошнім выпадку выкарыстоўвайце камбінацыю Shift+Caps Lock для звычайнага пераключэння Caps). Іншым папулярным выбарам ёсць камбінацыя Alt+Shift; тады яна згубіць свой эфект у Emacs ды іншых праграмах.\n\nНе ўсе паказаныя кнопкі прысутнічаюць на ўсіх клавіятурах.
Extended_description-bg.utf-8: Вашата клавиатурна подредба изисква начин за превключване между режим „латиница“ и режим „национални букви“.\n\nДесният клавиш Alt и клавишът Caps Lock често се избират от съображения за ергономичност (в последния случай използвайте комбинацията Shift+Caps Lock за нормален Caps Lock).  Комбинацията Alt+Shift също е популярен избор; тя обаче ще изгуби обичайното си действие в Emacs и други програми, които я използват за специфичните си нужди.\n\nНе всеки от изброените клавиши е наличен на всички клавиатури.
Extended_description-bn.utf-8: কীবোর্ডর ন্যাশনাল লেআউট ও ল্যাটিন লেআউটের মধ্যে টগল করতে আপনার একটা উপায় পেতে হবে।\n\nডান Alt বা Caps Lock কীগুলি প্রায়শই এর্গোনোমিক কারণে বেছে নেওয়া হয় (দ্বিতীয় ক্ষেত্রে, সাধারণ ক্যাপ টগলের জন্য Shift+Caps Lock ব্যবহার করুন)। Alt+Shift ও ব্যবহার হয়; তবে এটি Emacs এবং অন্যান্য প্রোগ্রামে, যেখানে এটির অন্য নির্দিষ্ট ব্যবহার আছে সেখানে কাজ করবে না।\n\nতালিকায় দেওয়া সমস্ত কীগুলি সব কীবোর্ডে থাকে না ।
Extended_description-bo.utf-8: རང་རྒྱལ་གྱི་བཀོད་པ་དང་ཚད་ལྡན་གྱི་ལ་ཐིན་བཀོད་པའི་བར་མཐེབ་གཞོང་བརྗེ་རེས་བྱེད་སྟངས་ཞིག་ཡོད་དགོས\n\nRight Alt or Caps Lock keys are often chosen for ergonomic reasons (in the latter case, use the combination Shift+Caps Lock for normal Caps toggle). Alt+Shift is also a popular combination; it will however lose its usual behavior in Emacs and other programs that use it for specific needs.\n\nཐོ་འགོད་བྱས་ཟིན་པའི་མཐེབ་ཆ་ཚང་མཐེབ་གཞོང་གང་རུང་ཐོག་ཏུ་མེད
Extended_description-bs.utf-8: Trebat će Vam način da prebacite tastaturu između nacionalnog rasporeda i standardnog Latinskog rasporeda.\n\nDesni Alt ili Caps Lock tipke su obično izabrani iz ergonomskih razloga (u drugom slučaju, koristite kombinaciju Shift+Caps Lock kao obični Caps prekidač). Alt+Shift je također popularna kombinacija; mada će izgubiti uobičajenu ulogu u Emacs i ostalim programima koji je koriste za svoje potrebe.\n\nSvi izlistani tasteri nisu prikazani na svim tastaturama.
Extended_description-ca.utf-8: Necessitareu una manera pera commutar el teclat entre la disposició nacional i la disposició llatina estàndard.\n\nSovint se seleccionen les tecles Alt dreta o Fixació de majúscules per raons d'ergonomia (en el segon cas, emrpreu la combinació Majúscules+Fixació de majúscules per a commutar la fixació normal). Alt+Majúscules també és una combinació habitual, tot i que perdrà el seu comportament habitual a l'Emacs i altres programes que l'empren per a necessitats específiques.\n\nNo totes les tecles llistades són presents a tots els teclats.
Extended_description-cs.utf-8: Potřebujete způsob, kterým se budete přepínat mezi vaším národním rozložením a standardním rozložením latinky.\n\nNejergonomičtější se zdá použití pravého Altu nebo Caps Lock (původní funkčnost Caps Lock pak získáte kombinací kláves Shift+Caps Lock). Další populární kombinací je Alt+Shift, případně Control+Shift. V takovém případě ale tato kombinace ztratí v aplikacích svůj původní význam (např. v Emacsu).\n\nUvedené klávesy nemusí být přítomny na všech klávesnicích.
Extended_description-cy.utf-8: Mi fydd yn rhaid i chi gael ffordd o newid y bysellfwrdd rhwng y cynllun cenedlaethol a'r cynllun Lladin safonol.\n\nDewisir y bysellau Alt Dde neu Capiau Clo fel arfer am resymau hwylustder (yn yr ail ddewis, defnyddiwch y cyfuniad Shift+Capiau Clo ar gyfer toglo llythrennau mawr arferol). Mae Alt+Shift yn gyfuniad poblogaidd hefyd; ond mi fydd yn colli ei ddefnydd arferol yn Emacs a rhaglenni eraill sy'n ei ddefnyddio at bwrpas penodol.\n\nNid yw'r bysellau rhestrwyd yn bresennol ar bob bysellfwrdd.
Extended_description-da.utf-8: Du har brug for en måde at skifte tastaturet mellem national-layoutet og standard-latin-layoutet.\n\nHøjre Alt eller Caps Lock-taster bliver ofte valgt af ergonomiske grunde (brug kombinationen Shift+Caps Lock til at slå Caps til/fra på normal vis i det tilfælde). Alt+Shift er også en populær kombination; kombinationen vil dog miste sin almindelige funktion i Emacs og andre programmer, der bruger den til særlige behov.\n\nIkke alle de viste taster er til stede på alle tastaturer.
Extended_description-de.utf-8: Sie benötigen eine Möglichkeit, die Tastaturbelegung zwischen nationalem und lateinischem Standardmodus umzuschalten.\n\nAus Ergonomiegründen werden oft die Alt- oder Feststelltasten ausgewählt. Im letzteren Fall verwenden Sie die Kombination Umschalttaste+Feststelltaste für das normale Umschalten der Großschreibung. Alt+Umschalttaste ist auch eine beliebte Kombination; in Emacs und anderen Programmen, die diese Kombination benutzen, wird sie allerdings ihre gewöhnliche Bedeutung verlieren.\n\nNicht alle aufgeführten Tasten sind auf allen Tastaturen vorhanden.
Extended_description-dz.utf-8: རྒྱལ་ཡོངས་སྒྲིག་བཀོད་དང་ཚད་ལྡན་ལེ་ཊིན་སྒྲིག་བཀོད་ཀྱི་བར་ན་ ལྡེ་སྒྲོམ་སོར་སྟོན་འབད་ནི་གི་དོན་ལུ་ ང་བཅས་ལུ་ཐབས་ལམ་དགོ།\n\nགཡས་ཀྱི་གདམ་ལྡེ་ ཡང་ན་ ཚུགས་ལྡེ་ཚུ་ ཨར་གོ་ནོ་མིག་གི་དོན་ལུ་ འཕྲལ་འཕྲལ་གདམ་ཁ་རྐྱབ་ཨིན། (ཤུལ་མའི་ཡི་གུ་ནང་ ཨ་རྟག་ཧ་ལུགས་ཀྱི་ཚུགས་ཡིག་སོར་སྟོན་འབད་ནི་ལུ་ མཉམ་བསྡོམས་ སོར་ལྡེ་+ཚུགས་ལྡེ་ལག་ལེན་འཐབ་) གདམ་ལྡེ་+སོར་ལྡེ་འདི་ ཡོངས་གྲགས་ཆེ་བའི་མཉམ་བསྡོམས་ཅིག་ཨིན། དམིགས་བསལ་དགོས་མཁོ་དང་འཁྲིལ་ཏེ་ལག་ལེན་འཐབ་མི་དེ་ ཨི་མེཀསི་དང་གཞན་ལས་རིམ་ཚུ་ནང་ ཨ་རྟག་་ལུགས་སྦེ་མི་གནས།\n\nཐོ་བཀོད་འབད་ཡོད་པའི་ལྡེ་ཡིག་ཆ་མཉམ་ ལྡེ་སྒྲོམ་ག་ར་ནང་མི་འོང་།
Extended_description-el.utf-8: Θα χρειαστείτε έναν τρόπο για την εναλλαγή μεταξύ τοπικής και της συνηθισμένης λατινικής διάταξης πληκτρολογίου.\n\nΤα πλήκτρα Right Alt ή Caps Lock επιλέγονται συνήθως για εργονομικούς λόγους (στη δεύτερη περίπτωση χρησιμοποιήστε τον συνδυασμό Shift+Caps Lock για τη συνηθισμένη εναλλαγή Κεφαλαίων). Ο συνδυασμός Alt+Shift είναι ένας επίσης δημοφιλής συνδυασμός. Χάνει όμως έτσι τη συνηθισμένη συμπεριφορά που έχει στον Emacs και σε άλλα προγράμματα όπου χρησιμοποιείται για ειδικές ανάγκες.\n\nΤα πλήκτρα που αναφέρονται εδώ δεν υπάρχουν σε όλα τα πληκτρολόγια.
Extended_description-eo.utf-8: Vi bezonos manieron por baskuli la klavaron inter la nacia aranĝo kaj la ordinara latina aranĝo.\n\nDekstra Alt aŭ Majuskla Baskula klavoj ofte estas elektitaj pro ergonomio (en la lasta situacio, uzu la kombinon Shift+Majusklo-baskulo por normala baskuligo). Alt+Shift ankaŭ estas populara kombino; tamen ĝi perdos sian normalan funkcion en Emacs kaj aliaj programoj kiuj uzas ĝin por specifaj bezonoj.\n\nNe ĉiu listita klavo ĉeestas en ĉiuj klavaroj.
Extended_description-es.utf-8: Necesitará una forma para cambiar el teclado entre la distribución nacional y la distribución latina estándar.\n\nLas teclas Alt derecho y Bloqueo mayúsculas se escogen frecuentemente por razones ergonómicas (en el último caso, utilice la combinación «Shift»+Bloqueo mayúsculas para cambiar a mayúsculas). Alt+«Shift» también es una combinación popular, sin embargo, perderá su comportamiento tradicional en Emacs y otros programas que las utilicen para sus propias necesidades.\n\nTenga en cuenta que las teclas listadas no están presentes en todos los teclados.
Extended_description-et.utf-8: Klaviatuuripaigutuse vahetamiseks rahvusliku ja standardse ladina-paigutuse vahel tuleb määrata vahetamise viis.\n\nErgonoomika tõttu valitakse tihti Parem Alt või Caps Lock klahvid (kasutatakse ka Shift+Caps Lock või harilikku Caps Lock lülitamist). Alt+Shift on samuti sage kombinatsioon, kuid siis kaotab see oma tavapärase kasutuse Emacs'is ja teistes programmides, mis seda kasutavad.\n\nMitte kõik loetletud klahvid ei ole saadaval kõigil klaviatuuridel.
Extended_description-eu.utf-8: Latin estandar eta nazionalaren diseinuen artean teklatua txandakatzeko aukera beharko duzu.\n\nArrazoi ergonomikoak direla eta aukeratu ohi dira Eskuineko Alt edo Blok. Maius teklak (azken kasuan, erabili Maius+Blokeatu Maiuskulak tamaina arruntera aldatzeko). Alt+Maius tekla-konbinazioa asko erabili ohi da baita ere; kontuan izan kasu honetan Alt+Maius tekla konbinazioak Emacs edo beste programetan duen erabilera galduko duela.\n\nZerrendatutako tekla guztiak ez daude teklatu guztietan.
Extended_description-fa.utf-8: نیاز به راهی برای تغییر وضعیت بین چینش ملّی و چینش استاندارد لاتین دارید.\n\nاغلب کلیدهای قفل تبدیل یا دگرساز راست به دلایل ارگونومی گزیده می‌شوند (در مورد نخست برای تغییر وضعیت بزرگی و کوچکی از تبدیل+قفل تبدیل استفاده کنید). دگرساز+تبدیل عم ترکیب محبوبی است؛ با این حال رفتار معمولش را در ای‌مکس و دیگر برنامه‌هایی که از این ترکیب برای نیازهای مشخّصی استفاده می‌کنند از دست می‌دهد.\n\nتمام کلید های فهرست شده روی تمامی صفحه‌کلیدها وجود ندارد.
Extended_description-fi.utf-8: Näppäinasettelua halutaan usein vaihtaa paikallisen ja standardin Latin-näppäinasettelun välillä.\n\nHelpoin näistä vaihtoehdoista on ehkä oikea Alt tai Caps Lock (käytä jälkimmäisessä tapauksessa yhdistelmää Vaihto+Caps Lock normaaliin kirjainkoon vaihtoon). Toinen suosittu vaihtoehto on yhdistelmä Alt+Vaihto, joka toisaalta ei valinnan jälkeen toimi normaalisti Emacsissa tai muissa yhdistelmää erityistarkoituksiin käyttävissä ohjelmissa.\n\nKaikkia lueteltuja näppäimiä ei ole kaikissa näppäimistöissä.
Extended_description-fr.utf-8: Il est nécessaire de disposer d'un moyen pour basculer entre la disposition nationale et la disposition latine normale.\n\nLes choix les plus ergonomiques semblent être la touche Alt de droite et la touche de verrouillage majuscule (dans ce dernier cas, utilisez la combinaison Majuscule + Verrouillage majuscule pour le basculement habituel en mode majuscule). Un autre choix populaire est la combinaison Alt + Majuscule. Cependant, dans ce cas, elle perdra sa fonction habituelle dans Emacs ou dans tout autre programme qui l'utiliserait pour un besoin spécifique.\n\nLes touches indiquées ne font pas partie de tous les claviers.
Extended_description-ga.utf-8: Teastaíonn uait modh scoránaithe idir an leagan amach náisiúnta agus an gnáthleagan amach Laidineach.\n\nBaintear úsáid as an eochair Alt ar dheis nó Caps Lock go minic, ar chúiseanna eirgeanamaice (sa dara cás, úsáid Shift+Caps Lock le haghaidh an ghnáthoibríocht Caps Lock). Baintear úsáid as Alt+Shift go minic freisin; ach sa chás seo ní bheidh a ghnáthoibríocht ar fáil in Emacs nó i ríomhchláir eile a úsáideann é.\n\nNíl gach eochair anseo ar fáil ar gach méarchlár.
Extended_description-gl.utf-8: Ha precisar dun sistema para conmutar o teclado entre a disposición nacional e a disposición Latin estándar.\n\nPolo xeral escóllense Alt dereita ou Bloq maiús por ergonomía (neste último caso empregue a combinación de Maiús+Bloq maiús para conmutar entre maiúsculas/minúsculas). Alt+Maiús tamén é unha combinación popular, aínda que ha perder o seu significado habitual en Emacs e outros programas que a usen con outros propósitos.\n\nNon todas as teclas da listaxe están presentes en todos os teclados.
Extended_description-gu.utf-8: તમને રાષ્ટ્રિય દેખાવ અને પ્રમાણભૂત લેટિન દેખાવ વચ્ચે કીબોર્ડ અદલા-બદલી કરવાની રીત જોઇશે.\n\nજમણી અલ્ટર અથવા કેપ્સ લોક કળો મોટાભાગે ઇર્ગોનોમિક કારણોસર (પછીના કિસ્સામાં, શીફ્ટ + કેપ્સ લોકનું જોડાણ સામાન્ય કેપ્સની બદલી માટે) પસંદ કરવામાં આવે છે. અલ્ટર+શીફ્ટ એ પણ લોકપ્રિય જોડાણ છે; તે જોકે ઈમેક્સ અને બીજા ચોક્કસ જરૂરિયાત વાળા ઉપયોગ કરતાંકાર્યક્રમોમાં તેમની સામાન્ય વર્તણૂક ગુમાવી દેશે.\n\nયાદી કરેલ બધી કળો બધાં કીબોર્ડમાં હાજર હોતી નથી.
Extended_description-he.utf-8: חייבת להיות דרך עבורך להעביר את המקלדת בין הפריסה המקומית שלך לבין הפריסה הלטינית התקנית.\n\nמקובל לבחור במקשים Alt ימני או ב־Caps Lock מסיבות ארגונומיות (במקרה השני, נא להשתמש בצירוף Shift+Caps Lock לטובת החלפת מצב אותיות גדולות). הצירוף Alt+Shift הוא גם כן צירוף מקובל, אך צירוף זה יאבד את התנהגותו הרגילה ב־Emacs ובתכניות אחרות שמשתמשות בצירוף למטרות מיוחדות.\n\nלא כל המקשים המופיעים נמצאים בכל המקלדות.
Extended_description-hi.utf-8: देशी तथा लैटिन मोड के बीच परिवर्तन करने की विधि आवश्यक है।\n\nश्रम-दक्षता के लिए दाहिना ऑल्ट या कैप्स लॉक कुंजी चुने जाते हैं (कैप्स लॉक चुना जाए तो परिवर्तन के लिए शिफ़्ट+कैप्स लॉक का उपयोग करें)। ऑल्ट +शिफ़्ट का भी उपयोग किया जा सकता है, पर Emacs जैसे कई प्रोग्राम में इनका साधारण उपयोग असंभव हो जाता है।\n\nदिखाए गए सारी कुंजी सारी कुंजीपटल पर उपलब्ध नहीं हैं।
Extended_description-hr.utf-8: Trebati ćete način za promjenu između nacionalnog i standardnog latinskog rasporeda.\n\nTipke desni Alt ili Caps Lock često su odabrane iz ergonomskih razloga (u potonjem slučaju, koristite Shift+Caps Lock za uobičajeno uključivanje i isključivanje upisa velikih slova). Alt+Shift je također popularna kombinacija; međutim, može izgubiti svoje uobičajeno ponašanje u Emacsu i ostalim programima posebne namjene.\n\nNisu sve tipke s popisa prisutne na svim tipkovnicama.
Extended_description-hu.utf-8: Szükség lesz egy nemzeti és latin kiosztás közti váltást biztosító módra.\n\nA jobb Alt vagy Caps Lock billentyűk gyakran választják ergonomikus okokból (az utóbbi esetben használja a Shift+Caps Lock kombinációt a szokásos Caps váltáshoz). Az Alt+Shift szintén népszerű kombináció, azonban elveszti szokásos jelentését az Emacs és más őt speciálisan használó programok alatt.\n\nNem minden felsorolt billentyű létezik minden billentyűzeten.
Extended_description-id.utf-8: Anda membutuhkan cara untuk berpindah antara pola keyboard nasional dan standar Latin.\n\nTombol Alt Kanan atau Caps Lock biasanya digunakan dengan alasan ergonomis (dalam kasus Caps Lock, gunakan kombinasi Shift+Caps Lock untuk berpindah ke Caps Lock biasa). Alt+Shift juga biasa digunakan, tetapi hal ini akan menghilangkan sarana pada Emacs dan program lainnya yang juga menggunakan kombinasi yang sama.\n\nTidak semua yang ditampilkan tersedia di semua keyboard.
Extended_description-is.utf-8: Þú munt þurfa einhverja leið til að skipta á milli staðbundinar uppsetningar og þeirrar sjálfgefnu latnesku.\n\nHægri-Alt eða Caps Lock lyklarnir eru oft valdir vegna þægilegrar líkamsbeitingar (í síðara tilfellinu ætti að nota saman Shift+Caps Lock fyrir venjulega CapsLock víxlun). Alt+Shift er líka vinsæl samsetning; hún missir hinsvegar sína venjulegu hegðun í Emacs og öðrum forritum sem nota þá samsetningu til sérstakra aðgerða.\n\nEkki eru allir lyklar sem taldir eru upp til staðar á öllum lyklaborðum.
Extended_description-it.utf-8: Sarà necessario avere un modo per commutare la tastiera fra disposizione nazionale e disposizione latina standard.\n\nPer motivi ergonomici vengono spesso usati i tasti Alt destro o Bloc Maiusc (in quest'ultimo caso, usare la combinazione Maiusc + Bloc Maiusc per la commutazione Maiusc normale). Anche Alt + Maiusc è una combinazione diffusa, ma non funzionerà in Emacs e negli altri programmi che la usano per scopi specifici.\n\nNon tutti i tasti elencati sono presenti in tutte le tastiere.
Extended_description-ja.utf-8: ナショナル配置と標準ラテン配置間でキーボードを切り換える方法が必要です。\n\n右 Alt または Caps Lock キーが人間工学的な理由でよく使われます (後者の場合、普通の Caps 切り替えには Shift+Caps Lockの組み合わせを使うことになります)。Alt+Shift も一般的な組み合わせのひとつですが、この組み合わせを特に必要とするような Emacs その他プログラムでの通常の動作を損うことになります。\n\n示されたすべてのキーがすべてのキーボードで提供されるわけではありません。
Extended_description-kab.utf-8: Ad teḥwiǧeḍ ttawil i useqluqel n unasiw gar tneɣruft taɣelnawt d tneɣruft talatinit taslugant.\n\nTiqeffalin Right Alt neɣ Caps Lock zgant ttufernent i ssebbat n unagrahal (deg tegnit-a taneggarut, seqdec tuddsa Shift+Caps Lock i uqluqel amagnu n Caps). Alt+Shift d tuddsa daɣen yettwassnen,; ad as-iruh wudem-is i nennum deg Emacs d wahilen ara tt-iseqdacen i yisuturen usdiden.\n\nMačči meṛṛa tisura yellan deg tebdart llant ɣef meṛṛa inasiwen.
Extended_description-kk.utf-8: Сізге пернетақтаның ұлттық пен латын жаймалары арасында ауысу жолы керек болады.\n\nОң жақ Alt немесе Caps Lock пернелері жиі ыңғайлылық есебінен қолданылады (соңғы жағдайда, қалыпты Caps ауыстыру үшін Shift+Caps Lock қолданылады). Alt+Shift тіркесі де жиі қолданылады; бірақта, ол тіркесті қолданатын Emacs немесе басқа қолданбалар оны жоғалтатын болады.\n\nТізілген пернелердің барлығы барлық пернетақталарда кездесе бермейді.
Extended_description-km.utf-8: អ្នក​​ត្រូវ​ការ​វិធី​មួយ​ ដើម្បី​បិទ/បើក​ក្ដារចុច​រវាង​ប្លង់​ភាសា​ជាតិ និង​ប្លង់​ឡាតាំង​ស្តង់ដារ ។\n\nគ្រាប់ចុច​ជំនួស (Alt) ឬ​ប្ដូរ​ជាប់ (Caps Lock) ​ជា​រឿយៗ​ត្រូវ​បាន​ជ្រើស​សម្រាប់​ហេតុផល ergonomic (នៅក្នុង​លក្ខណៈ​អក្សរ ប្រើ​បន្សំ​គ្រាប់ចុច​ប្ដូរ (Shift)+ ប្ដូរ​ជាប់ (Caps Lock) សម្រាប់​បិទ/បើក​ប្ដូរ​ជាប់ (Caps)) ។ ជំនួស(Alt)+ប្ដូរ (Shift) គឺ​ជា​បន្សំ​ដ៏​មាន​ប្រជាប្រិយភាព វា​នឹង​បាត់បង់​ឥរិយាបថ​ធម្មតា​របស់​វា​នៅ​ក្នុង Emacs និង​កម្មវិធី​ផ្សេង​ៗ​ទៀត​ដែលប្រើ​វា​សម្រាប់​តម្រូវការ​ជាក់លាក់​ ។\n\nមិនមែន​គ្រប់​ចុច​ដែល​បាន​រាយ​ទាំងអស់​បង្ហាញ​នៅ​លើ​ក្ដារចុច​ទាំង​អស់​ទេ ។
Extended_description-kn.utf-8: ನಿಮಗೆ ರಾಷ್ಟ್ರೀಯ ಹಾಗು ಲ್ಯಾಟಿನ್ ವಿಧಾನಗಳ ನಡುವೆ ಕೀಲಿಮಣೆಯನ್ನು ಅದಲುಬದಲು ಮಾಡಲು ಒಂದು ದಾರಿ ಬೇಕಾಗಬಹುದು\n\nಬಲ ಆಲ್ಟ್ ಅಥವಾ ಕ್ಯಪ್ಸ್ ಲಾಕ್ ಕೀಲಿಗಳನ್ನು ಸಾಮಾನ್ಯವಾಗಿ ದಕ್ಷತಾಶಾಸ್ತ್ರದ ಕಾರಣಗಳಿಂದಾಗಿ ಆಯ್ಕೆ ಮಾಡಲಾಗುತ್ತದೆ (ಎರಡನೆ ಸಂಧರ್ಭದಲ್ಲಿ ಸಮಾನ್ಯ ಕ್ಯಾಪ್ಸ್ ಅದಲು-ಬದಲು ಮಾಡಲು ಶಿಫ್ಟ್ + ಕ್ಯಾಪ್ಸ್ ಲಾಕ್  ಸಂಯೋಜನೆಯನ್ನು ಬಳಸಿ)\n\nಪಟ್ಟಿ ಮಾಡಿದ ಎಲ್ಲಾ ಕೀಲಿಗಳು ಎಲ್ಲ ಕೀಲಿಮಣೆಗಳ ಮೇಲೆ ಇರಬೇಕೆಂದಿಲ್ಲ
Extended_description-ko.utf-8: 지역 키보드 배치와 기본 영문 키보드 사이에 토글할 방법이 필요합니다.\n\n오른쪽 Alt 또는 Caps Lock 키를 (사용하기 편리하므로) 주로 사용합니다. (Caps Lock 키를 사용할 경우 일반 Caps Lock 토글 목적으로는 Shift+Caps Lock을 사용합니다.) Alt+Shift 키도 많이 사용하는 조합이지만, 이맥스 및 기타 프로그램의 기능에서 이 키 조합을 사용할 수 없게 됩니다.\n\n키보드에 따라 목록의 키가 모두 없는 키보드도 있습니다.
Extended_description-ku.utf-8: Ji bo guherandina di navbera neteweyî û latîniya standard de ji te re rêbazek divê.\n\nBişkojên Rast Alt an jî Caps Lock ji ber sedemên ergonomîk têne hilbijartin (di nivîsandinê de kombînasyona Shift+Caps Lock ji bo guherandina asayî ya Capsê de bi kar bîne). Her wiha Alt+Shift kombînasyona populer e.\n\nHişyarbe ku bişkojên lîstekirî di hemû klavyeyan de tune ne.
Extended_description-lo.utf-8: ທ່ານຈະຕ້ອງມີວິທີການສັບປ່ຽນໂຄງຮ່າງແປ້ນພິມລະຫວ່າງປະເທດແລະຮູບແບບລາຕິນມາດຕະຖານ\n\nAlt ຂວາຫລືປຸ່ມ Caps Lock ຖືກເລືອກສ່ວນຫລາຍຈະດ້ວຍເຫດຜົນທາງວິທະຍາສາດ (ໃນກໍລະນີຫລັງນີ້ໃຊ້ປະສົມປະສານລະຫວ່າງ Shift+Caps Lock ເພື່ອສັບປ່ຽນCaps ປົກກະຕິ). Alt+Shift ນີ້ຍັງມີການຮ່ວມກັນທີ່ນິຍົມໃຊ້ກັນກໍ່ຈະສູນເສຍ ແຕ່ພຶດຕິກຳປົກກະຕິໃນ Emacs ແລະໂປຣແກມອື່ນໆ ທີ່ໃຊ້ສຳຫລັບຄວາມຕ້ອງການສະເພາະ\n\nບໍ່ທັ້ງໝົດຄີລະບຸໄວ້ນີ້ສະແດງເທິງແປ້ນທັ້ງໝົດ
Extended_description-lt.utf-8: Jums prireiks būdo perjungti klaviatūros išdėstymą iš nacionalinio į bazinį lotynišką ir atgal.\n\nErgonomikos sumetimais dažnai pasirenkamas dešinysis Alt arba Didž klavišas (pastaruoju atveju didžiosios raidės gali būti fiksuojamos klavišų kombinacija Lyg2+Didž). Taip pat populiari Alt+Lyg2 kombinacija, tačiau tuomet ji praranda savo įprastą funkciją „Emacs“ ir kitose ją naudojančiose programose.\n\nNe visus išvardytus klavišus galima rasti visose klaviatūrose.
Extended_description-lv.utf-8: Ar šo taustiņu kombināciju varēs pārslēgties starp izvēlēto nacionālo tastatūras izkārtojumu un standarta latīņu izkārtojumu.\n\nErgonomisku apsvērumu dēļ bieži tiek lietoti taustiņi Labais Alt un Caps Lock (izvēloties šo variantu var lietot Shift+Caps Lock, lai izmantotu standarta Caps Lock funkciju). Bieži tiek lietota arī taustiņu kombinācija Alt+Shift; taču tad tiek zaudēta iespēja lietot šo kombināciju Emacs programmā un dažās citos specifiskos pielietojumos.\n\nNe visi taustiņu sarakstā ir pieejamas uz visām tastatūrām.
Extended_description-mk.utf-8: Ќе Ви треба начин да менувате меѓу националниот и стандардниот латиничен распоред.\n\nRight Alt или Caps Lock копчињата се често бирани поради ергономски причини (во вториот случај, користете ја комбинацијата Shift+Caps Lock за нормално Caps менување). Alt+Shift е исто така популарна комбинација; но ќе го изгуби вообичаеното однесување во Emacs и други програми кои ја користат за специфични потреби.\n\nНекои тастатури ги немаат сите прикажани копчиња.
Extended_description-ml.utf-8: സാധാരണ കാണുന്ന ലാറ്റിന്‍ വിന്യാസവും ദേശീയ വിന്യാസവും തമ്മില്‍ മാറ്റുന്നതിനു് നിങ്ങളൊരു വഴി കാണണം.\n\nആരോഗ്യ കാരണങ്ങളാല്‍ വലതുവശത്തെ ആള്‍ട്ട് അല്ലെങ്കില്‍ കാപ്സ് ലോക്ക് കീകളാണു് സാധാരണയായി എടുക്കാറു് (രണ്ടാമത്തേതാണെങ്കില്‍ ഷിഫ്റ്റ് + കാപ്സ് ലോക്ക് എന്നിവ ഒന്നിച്ചുപയോഗിച്ചു് സാധാരണ കാപ്സ് ലോക്ക് ഉപയോഗം നടത്താം). ആള്‍ട്ട് + ഷിഫ്റ്റ് എന്നതും സാധാരണയായി തെരഞ്ഞെടുക്കുന്നതാണു്; പക്ഷേ പ്രത്യേകാവശ്യത്തിനു് ഇവയുപയോഗിയ്ക്കുന്ന ഈമാക്സിലും മറ്റു പ്രോഗ്രാമുകളിലും ഇതിന്റെ സാധാരണ പെരുമാറ്റം നഷ്ടപ്പെടും.\n\nനിങ്ങള്‍ നല്‍കിയ കീകളെല്ലാം എല്ലാ കീബോര്‍ഡുകളിലുമുള്ളതല്ല.
Extended_description-mr.utf-8: नॅशनल आराखडा व प्रमाण लॅटिन आराखडा यांदरम्यान टॉगलिंग करण्यासाठी आपल्याला एखादी पद्धत ठरवणे गरजेचे आहे.\n\nसोयीकरिता उजवी Alt वा Caps Lock कळी या कळी बहुतेकदा निवडल्या जातात ( नंतरच्या केसमध्ये, नेहमीच्या Caps टॉगलकरिता Shift+Caps Lock संयोग वापरा). Alt+Shift हा संयोगसुद्धा प्रसिद्ध आहे; पण त्यामुळे त्याचे Emacs व अन्य प्रोग्रॅम मधील विशिष्ट गरजां करिता वापरले जाणारे नेहमीचे वर्तन बंद होईल.\n\nनोंदलेल्या सर्व कळी सर्वच कळफलकांवर उपलब्ध असतातच असे नाही.
Extended_description-nb.utf-8: Du trenger en måte å skifte mellom tastatur med nasjonal utforming og standard latinsk utformingen.\n\nHøyre Alt eller Caps Lock brukes ofte av ergonomiske grunner. Alt + Shift er også en populær kombinasjon. Den vil imidlertid miste sin vanlig oppførsel i Emacs og andre program som bruker kombinasjon internt.\n\nIkke alle listede taster fins på alle tastatur.
Extended_description-ne.utf-8: देशी तथा लैटिन मोड को बीचमा परिवर्तन गर्ने एक तरिका आवश्यक छ.\n\nदाहिने Alt वा क्याप्स लक कुञ्जीहरू अक्सर ergonomic कारणहरूका लागि चयन गरिन्छ (पछिल्लो अवस्थामा, सामान्य Caps टगलका लागि Shift + Caps Lock को प्रयोग गर्नुहोस्)। Alt + Shift पनि एक लोकप्रिय संयोजन हो। यो तथापि इमैक र अन्य कार्यक्रमहरूमा यसको सामान्य व्यवहार गुमाउने छ जुन यसको विशिष्ट आवश्यकताका लागि प्रयोग गर्दछ।\n\nसबै सूचीबद्ध कुञ्जीहरू सबै कीबोर्डमा रहेका छैनन्।
Extended_description-nl.utf-8: Er is een methode nodig om het toetsenbord te kunnen schakelen tussen de nationale indeling en de standaard Latijnse indeling.\n\nHiervoor worden om ergonomische redenen vaak de toetsen Alt-Rechts of Caps Lock gekozen (gebruik in het laatste geval de combinatie Shift+Caps Lock om de normale Caps Lock te schakelen). Alt+Shift is ook een populaire combinatie, maar dat zal dan wel zijn functie in Emacs en andere programma's waar het een bijzondere functie heeft verliezen.\n\nNiet alle vermelde toetsen komen voor op alle toetsenborden.
Extended_description-nn.utf-8: Du treng ein måte å skifte tastaturet mellom nasjonal utforming og standard latinsk utforming.\n\nHøgre Alt eller Caps Lock blir ofte brukt av ergonomiske grunnar (i det siste tilfellet bruk kombinasjonen Shift + Caps Lock for vanleg Caps-oppførsel). Alt+Shift er òg ein vanleg kombinasjon, men den mister den vanlege oppførselen i Emacs og andre program som bruker den av særskilde grunnar.\n\nIkkje alle oppgitte tastar finst på alle tastatur.
Extended_description-no.utf-8: Du trenger en måte å skifte mellom tastatur med nasjonal utforming og standard latinsk utformingen.\n\nHøyre Alt eller Caps Lock brukes ofte av ergonomiske grunner. Alt + Shift er også en populær kombinasjon. Den vil imidlertid miste sin vanlig oppførsel i Emacs og andre program som bruker kombinasjon internt.\n\nIkke alle listede taster fins på alle tastatur.
Extended_description-oc.utf-8: Es necessari de dispausar d'un mejan per bascular entre la disposicion nacionala e la disposicion latina normala.\n\nLas causidas mai ergonomicas semblan èsser la tòca Alt de drecha e la tòca de verrolhatge majuscula (dins aquel darrièr cas, utilizatz la combinason Majuscula + Verrolhatge majuscula pel basculament costumièr en mòde majuscula). Una autre causida populara es la combinason Alt + Majuscula. Çaquelà, dins aquel cas, perdrà sa foncion costumièra dins Emacs o dins tot autre programa que l'utilizariá per un besonh especific.\n\nLas tòcas indicadas fan pas partida de totes los clavièrs.
Extended_description-pa.utf-8: ਤੁਹਾਨੂੰ ਰਾਸ਼ਟਰੀ ਲੇਆਉਟ ਤੇ ਸਟੈਂਡਰਡ ਲਾਤੀਨੀ ਲੇਆਉਟ ਵਿੱਚ ਬਦਲਣ ਦਾ ਤਰੀਕਾ ਚਾਹੀਦਾ ਹੋਵੇਗਾ।\n\nਏਰਗੋਨੋਮਿਕ ਕਾਰਨਾਂ ਕਰਕੇ ਸੱਜੀ Alt ਜਾਂ Caps Lock ਸਵਿੱਚ ਆਮ ਤੋਰ ਤੇ ਚੁਣੇ ਜਾਂਦੇ ਹਨ (ਮਗਰਲੇ ਕੇਸ ਵਿੱਚ Shift+Caps Lock ਆਮ Caps ਬਦਲਣ ਲਈ ਵਰਤੋ)। Alt+Shift ਦਾ ਜੋੜ ਆਮ ਵਰਤਿਆ ਜਾਂਦਾ ਏ, ਪਰ ਈਮੈਕਸ ਤੇ ਹੋਰ ਪਰੋਗਰਾਮ, ਜਿੰਨਾ ਦੀਆਂ ਇਸ ਜੋੜ ਤੋਂ ਸਪੈਸ਼ਲ ਲੋੜ ਏ, ਵਿੱਚ ਇਹ ਆਪਣਾ ਆਮ ਸੁਭਾਅ ਗਵਾ ਦਿੰਦਾ ਹੈ।\n\nਸਾਰੀਆਂ ਦਰਸਾਈਆਂ ਸਵਿੱਚਾਂ ਇਸ ਕੀ-ਬੋਰਡ ਤੇ ਮੋਜੂਦ ਨਹੀਂ ।
Extended_description-pl.utf-8: Potrzebny będzie sposób przełączania klawiatury pomiędzy układem narodowym a standardowym układem łacińskim.\n\nZ powodów ergonomii często wybiera się prawy klawisz Alt lub Caps Lock (w tym drugim przypadku zwykła funkcja Caps Lock jest dostępna w kombinacji z klawiszem Shift). Innym popularnym ustawieniem jest Alt+Shift, jednak ta kombinacja straci swoje zachowanie w programie Emacs lub innych, które używają je do swoich potrzeb.\n\nNie wszystkie wymienione klawisze są dostępne na wszystkich klawiaturach.
Extended_description-pt.utf-8: Precisa de um modo de alternar o teclado entre a disposição nacional e o padrão Latin.\n\nAltGr ou Caps Lock são escolhidos muitas vezes por razões ergonómicas (neste último caso para ligar as maiúsculas usa-se Shift+Caps Lock). Alt+Shift é também uma combinação popular; no entanto perderá o seu significado habitual no Emacs e noutros programas que fazem uso dela.\n\nNem todas as teclas referidas estão presentes em todos os teclados.
Extended_description-pt_br.utf-8: Você precisará de uma maneira para alternar o teclado entre o layout nacional e o layout padrão Latin.\n\nAs teclas Alt Direito ou Caps Lock são frequentemente escolhidas por razões ergonômicas (neste último caso, use a combinação Shift+Caps Lock para uma alternância normal de Caps). Alt+Shift também é uma combinação popular; no entanto, ela perderá seu comportamento habitual no Emacs e em outros programas que a usam para necessidades específicas.\n\nNem todas as teclas listadas estão presentes em todos os teclados.
Extended_description-ro.utf-8: Veți avea nevoie de o metodă de a comuta tastatura între aranjamentul național și cel standard latin.\n\nTastele Alt dreapta sau Caps Lock sunt frecvent alese din motive de ergonomie (pentru cea din urmă, folosiți Shift+Caps Lock pentru comutarea între litere mici și litere mari). Alt+Shift este și ea o combinație populară; totuși i se va pierde comportamentul în Emacs și în alte programe care o folosesc deja.\n\nUnele din tastele afișate aici pot lipsi de pe unele tastaturi.
Extended_description-ru.utf-8: Вам нужно указать способ переключения клавиатуры между национальной раскладкой и стандартной латинской раскладкой.\n\nНаиболее эргономичным способом считаются правая клавиша Alt или Caps Lock (в последнем случае для переключения между заглавными и строчными буквами используется комбинация Shift+Caps Lock). Ещё одна популярная комбинация: Alt+Shift; заметим, что в этом случае комбинация Alt+Shift потеряет своё привычное действие в Emacs и других, использующих её, программах.\n\nНе на всех клавиатурах есть перечисленные клавиши.
Extended_description-si.utf-8: ඔබට යතුරුපුවරුව ජාතික සැකැස්ම හා සම්මත ලතින් සැකැස්ම අතර මාරුවීමේ ක්‍රමයක් අවශ්‍යයි.\n\nදකුණු Alt යතුර හෝ Caps අගුළු යතුර බොහෝවිට කාර්යක්‍ෂමතා හේතූන් සඳහා යොදාගැනේ (දෙවන කරුණේදී, Shift+Caps අගුළු යතුරු සංයුක්තය සාමාන්‍ය Caps මාරුවට යොදාගැනේ). Alt +Shift යනුද ප්‍රකට සංයුක්තයකි; කෙසේවුවත් එය Emacs හෝ එවැනි විශේෂ කාර්යයන් භාවිත වන වැඩසටහන් වලදී සාමාන්‍ය හැසිරීම හැරදමයි.\n\nලැයිස්තු ගත කර ඇති සියළුම යතුරු සෑම යතුරුපුවරුවකම දක්නට නැත.
Extended_description-sk.utf-8: Budete potrebovať spôsob prepínania medzi národným rozložením a štandardným rozložením Latin.\n\nZ  ergonomických dôvodov sa často sa volia klávesy pravý Alt alebo Caps Lock (v druhom prípade použite na normálne prepnutie veľkosti písmen Shift+Caps Lock). Alt+Shift je tiež populárna kombinácia; tým však stratí mnoho zo svojho pôvodného významu v Emacs a iným programoch, ktoré ho využívajú.\n\nNie všetky uvedené klávesy sa nachádzajú na všetkých klávesniciach.
Extended_description-sl.utf-8: Potrebujete način, da tipkovnica preide iz narodne razporeditve na standardno razporeditev Latin.\n\nIz ergonomskih razlogov se pogosto izbere Desno izmenjalko ali Caps Lock (v tem primeru uporabite kombinacijo Dvigalka+Caps Lock za običajen preklop velikih črk). Izmenjalka+Dvigalka je tudi razširjena kombinacija; pri tem se bo pa izgubila običajna uporaba v programu Emacs in drugih programih, ki to kombinacijo uporabljajo za svoje specifičen potrebe.\n\nTipke na spisku niso vedno prisotne na vseh tipkovnicah.
Extended_description-sq.utf-8: Ju duhet një mënyrë për të këmbyer tastierën mes paraqitjes nacionale dheparaqitjes standarde Latine\n\nAlt i djathte ose Caps lock zgjidhen zakonisht per arsye ergonomike (në rastin e fundit, përdor kombinimin Shift+Caps Lock për Caps toggle normal). Alt+Shift është gjithashtu një kombinim i njohur; megjithatë do te humbasi sjelljen e tij të zakonshme në Emacs dhe programe të tjera mund ta përdorin për nevoja specifike.\n\nJo të gjithë çelësat e rradhitur janë prezent në të gjithe tastierët.
Extended_description-sr.utf-8: Требаће вам начин за пребацивање тастатуре на национални или латинични распоред.\n\nДесни Alt или Caps Lock тастери обично се користе због ергономских разлога (уколико се користи Caps Lock, пребацивање на велика и мала слова се врши помоћу Shift+Caps Lock). Популарна комбинација је и Alt+Shift, али се тако губе неке функције Emacs едитора и осталих програма који користе ту комбинацију.\n\nНису сви излистани тастери присутни на свим тастатурама.
Extended_description-sr@latin.utf-8: Trebaće vam način za prebacivanje tastature na nacionalni ili latinični raspored.\n\nDesni Alt ili Caps Lock tasteri obično se koriste zbog ergonomskih razloga (ukoliko se koristi Caps Lock, prebacivanje na velika i mala slova se vrši pomoću Shift+Caps Lock). Popularna kombinacija je i Alt+Shift, ali se tako gube neke funkcije Emacs editora i ostalih programa koji koriste tu kombinaciju.\n\nNisu svi izlistani tasteri prisutni na svim tastaturama.
Extended_description-sv.utf-8: Du behöver ett sätt att byta tangentbordslayout mellan din nationella layout och Latin som är standardvalet.\n\nDet mest ergonomiska valet verkar vara höger Alt- och Caps Lock-tangenterna. Ett annat vanligt val är kombinationen Alt+Shift, här ska man dock vara medveten om att en del program (t.ex. Emacs) använder sig av denna kombination till andra saker och dessa blir därmed omöjliga att utföra.\n\nKom ihåg att alla tangenterna som anges här inte finns på alla tangentbord.
Extended_description-ta.utf-8: தேசிய இட அமைவு மற்றும் செந்தர இலத்தீன் இட அமைவுகளுக்கு இடையே பாங்குகளுக்கு நிலை மாற்றுதலுக்கு ஒரு முறை தேவையிருக்கும்.\n\nஉயிரியல்சார் தொழிலமைப்பு காரணங்களுக்காக வலது ஆல்ட் அல்லது கேப்ஸ் விசைகள் தேர்ந்தெடுக்கப்படுகின்றன. பின்னதில் வழக்கமான மேல் கீழ் நிலை எழுத்து நிலை மாற்றத்துக்கு ஷிப்ட்+கேப்ஸ் பூட்டு விசைஜோடியை பயன்படுத்தவும். ஆல்ட்+ஷிப்ட் கூட பரவலான ஜோடியாகும். ஆயின் ஈமேக்ஸ் மற்றும் சில நிரல்களில் இவைகுறிப்பிட்ட தேவைகளுக்கு பயனாவதால் அவற்றின் வழக்கமான நடத்தை மாறிவிடும்.\n\nபட்டியலிட்ட அனைத்து விசைகளும் அனத்து விசைப்பலகைகளிலும் இரா.
Extended_description-te.utf-8: కీ బోర్డు ను జాతీయ లేఔట్ మరియు ప్రామాణిక లాటిన్ లేఔట్ కి మార్చుటకు పద్ధతి కావాలి.\n\nకుడి ఆల్ట్ లేక కేప్స్ లాక్  కీలు సౌకర్యవంతంగా వుండటానికి  ఎంచుకుంటారు(రెండవది వాడేటప్పుడు షిఫ్ట్+ కేప్స్ లాక్ వాడి మామూలు కేప్స్ లాక్ కి మారవచ్చు). ఆల్ట్ + షిఫ్ట్ కూడా ప్రజాదరణ పొందినది; కాని ఈమాక్స్ మరియి ఇతర ప్రోగ్రాములలో ప్రత్యేక అవసరం కోసం వాడబడుతుంది.\n\nజాబితా లోని కీలన్నీ అన్ని కీబోర్డు లేఔట్ల మీద లేవు.
Extended_description-tg.utf-8: Ба шумо усуле лозим мешавад, ки ҳарфкалидро дар байни тарҳбандии миллӣ ва тарҳбандии стандартии лотинӣ интихоб мекунад.\n\nТугмаҳои Alt-и рост ё Caps Lock одатан барои сабабҳои эргономӣ интихоб карда мешаванд (дар ҳолати пешина, вобастагии тугмаҳои Shift+Caps Lock-ро барои интихобкунии муқаррарии ҳарфҳои калон истифода баред). Alt+Shift низ вобастагии машҳур мебошад; аммо, он рафтори оддии худро дар Emacs ва барномаҳои дигаре, ки онро барои эҳтиёҷоти мушаххаси худ истифода мебаранд, гум мекунад.\n\nНа ҳамаи тугмаҳои номбаршуда дар ҳамаи ҳарфкалидҳо мавҷуданд.
Extended_description-th.utf-8: คุณต้องกำหนดวิธีสลับภาษาแป้นพิมพ์ ระหว่างผังภาษาท้องถิ่นกับผังละตินมาตรฐาน\n\nAlt ขวา และ Caps Lock เป็นตัวเลือกที่มักจะเลือกกัน ด้วยเหตุผลด้านสุขลักษณะ (โดยในกรณีหลัง คุณสามารถใช้ Shift+Caps Lock สำหรับการยกแคร่ค้างตามปกติได้) ในขณะที่ Alt+Shift ก็เป็นตัวเลือกยอดนิยม แต่การใช้ปุ่มดังกล่าวจะทำให้ไม่สามารถใช้ Alt+Shift ตามปกติใน Emacs และโปรแกรมอื่นๆ ที่ใชpackage File::Temp; # git description: v0.2310-3-gc7148fe
# ABSTRACT: return name and handle of a temporary file safely

our $VERSION = '0.2311';

#pod =begin :__INTERNALS
#pod
#pod =head1 PORTABILITY
#pod
#pod This section is at the top in order to provide easier access to
#pod porters.  It is not expected to be rendered by a standard pod
#pod formatting tool. Please skip straight to the SYNOPSIS section if you
#pod are not trying to port this module to a new platform.
#pod
#pod This module is designed to be portable across operating systems and it
#pod currently supports Unix, VMS, DOS, OS/2, Windows and Mac OS
#pod (Classic). When porting to a new OS there are generally three main
#pod issues that have to be solved:
#pod
#pod =over 4
#pod
#pod =item *
#pod
#pod Can the OS unlink an open file? If it can not then the
#pod C<_can_unlink_opened_file> method should be modified.
#pod
#pod =item *
#pod
#pod Are the return values from C<stat> reliable? By default all the
#pod return values from C<stat> are compared when unlinking a temporary
#pod file using the filename and the handle. Operating systems other than
#pod unix do not always have valid entries in all fields. If utility function
#pod C<File::Temp::unlink0> fails then the C<stat> comparison should be
#pod modified accordingly.
#pod
#pod =item *
#pod
#pod Security. Systems that can not support a test for the sticky bit
#pod on a directory can not use the MEDIUM and HIGH security tests.
#pod The C<_can_do_level> method should be modified accordingly.
#pod
#pod =back
#pod
#pod =end :__INTERNALS
#pod
#pod =head1 SYNOPSIS
#pod
#pod   use File::Temp qw/ tempfile tempdir /;
#pod
#pod   $fh = tempfile();
#pod   ($fh, $filename) = tempfile();
#pod
#pod   ($fh, $filename) = tempfile( $template, DIR => $dir);
#pod   ($fh, $filename) = tempfile( $template, SUFFIX => '.dat');
#pod   ($fh, $filename) = tempfile( $template, TMPDIR => 1 );
#pod
#pod   binmode( $fh, ":utf8" );
#pod
#pod   $dir = tempdir( CLEANUP => 1 );
#pod   ($fh, $filename) = tempfile( DIR => $dir );
#pod
#pod Object interface:
#pod
#pod   require File::Temp;
#pod   use File::Temp ();
#pod   use File::Temp qw/ :seekable /;
#pod
#pod   $fh = File::Temp->new();
#pod   $fname = $fh->filename;
#pod
#pod   $fh = File::Temp->new(TEMPLATE => $template);
#pod   $fname = $fh->filename;
#pod
#pod   $tmp = File::Temp->new( UNLINK => 0, SUFFIX => '.dat' );
#pod   print $tmp "Some data\n";
#pod   print "Filename is $tmp\n";
#pod   $tmp->seek( 0, SEEK_END );
#pod
#pod   $dir = File::Temp->newdir(); # CLEANUP => 1 by default
#pod
#pod The following interfaces are provided for compatibility with
#pod existing APIs. They should not be used in new code.
#pod
#pod MkTemp family:
#pod
#pod   use File::Temp qw/ :mktemp  /;
#pod
#pod   ($fh, $file) = mkstemp( "tmpfileXXXXX" );
#pod   ($fh, $file) = mkstemps( "tmpfileXXXXXX", $suffix);
#pod
#pod   $tmpdir = mkdtemp( $template );
#pod
#pod   $unopened_file = mktemp( $template );
#pod
#pod POSIX functions:
#pod
#pod   use File::Temp qw/ :POSIX /;
#pod
#pod   $file = tmpnam();
#pod   $fh = tmpfile();
#pod
#pod   ($fh, $file) = tmpnam();
#pod
#pod Compatibility functions:
#pod
#pod   $unopened_file = File::Temp::tempnam( $dir, $pfx );
#pod
#pod =head1 DESCRIPTION
#pod
#pod C<File::Temp> can be used to create and open temporary files in a safe
#pod way.  There is both a function interface and an object-oriented
#pod interface.  The File::Temp constructor or the tempfile() function can
#pod be used to return the name and the open filehandle of a temporary
#pod file.  The tempdir() function can be used to create a temporary
#pod directory.
#pod
#pod The security aspect of temporary file creation is emphasized such that
#pod a filehandle and filename are returned together.  This helps guarantee
#pod that a race condition can not occur where the temporary file is
#pod created by another process between checking for the existence of the
#pod file and its opening.  Additional security levels are provided to
#pod check, for example, that the sticky bit is set on world writable
#pod directories.  See L<"safe_level"> for more information.
#pod
#pod For compatibility with popular C library functions, Perl implementations of
#pod the mkstemp() family of functions are provided. These are, mkstemp(),
#pod mkstemps(), mkdtemp() and mktemp().
#pod
#pod Additionally, implementations of the standard L<POSIX|POSIX>
#pod tmpnam() and tmpfile() functions are provided if required.
#pod
#pod Implementations of mktemp(), tmpnam(), and tempnam() are provided,
#pod but should be used with caution since they return only a filename
#pod that was valid when function was called, so cannot guarantee
#pod that the file will not exist by the time the caller opens the filename.
#pod
#pod Filehandles returned by these functions support the seekable methods.
#pod
#pod =cut

# Toolchain targets v5.8.1, but we'll try to support back to v5.6 anyway.
# It might be possible to make this v5.5, but many v5.6isms are creeping
# into the code and tests.
use 5.006;
use strict;
use Carp;
use File::Spec 0.8;
use Cwd ();
use File::Path 2.06 qw/ rmtree /;
use Fcntl 1.03;
use IO::Seekable;               # For SEEK_*
use Errno;
use Scalar::Util 'refaddr';
require VMS::Stdio if $^O eq 'VMS';

# pre-emptively load Carp::Heavy. If we don't when we run out of file
# handles and attempt to call croak() we get an error message telling
# us that Carp::Heavy won't load rather than an error telling us we
# have run out of file handles. We either preload croak() or we
# switch the calls to croak from _gettemp() to use die.
eval { require Carp::Heavy; };

# Need the Symbol package if we are running older perl
require Symbol if $] < 5.006;

### For the OO interface
use parent 0.221 qw/ IO::Handle IO::Seekable /;
use overload '""' => "STRINGIFY", '0+' => "NUMIFY",
  fallback => 1;

our $DEBUG = 0;
our $KEEP_ALL = 0;

# We are exporting functions

use Exporter 5.57 'import';   # 5.57 lets us import 'import'

# Export list - to allow fine tuning of export table

our @EXPORT_OK = qw{
                 tempfile
                 tempdir
                 tmpnam
                 tmpfile
                 mktemp
                 mkstemp
                 mkstemps
                 mkdtemp
                 unlink0
                 cleanup
                 SEEK_SET
                 SEEK_CUR
                 SEEK_END
             };

# Groups of functions for export

our %EXPORT_TAGS = (
                'POSIX' => [qw/ tmpnam tmpfile /],
                'mktemp' => [qw/ mktemp mkstemp mkstemps mkdtemp/],
                'seekable' => [qw/ SEEK_SET SEEK_CUR SEEK_END /],
               );

# add contents of these tags to @EXPORT
Exporter::export_tags('POSIX','mktemp','seekable');

# This is a list of characters that can be used in random filenames

my @CHARS = (qw/ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
                 a b c d e f g h i j k l m n o p q r s t u v w x y z
                 0 1 2 3 4 5 6 7 8 9 _
               /);

# Maximum number of tries to make a temp file before failing

use constant MAX_TRIES => 1000;

# Minimum number of X characters that should be in a template
use constant MINX => 4;

# Default template when no template supplied

use constant TEMPXXX => 'X' x 10;

# Constants for the security level

use constant STANDARD => 0;
use constant MEDIUM   => 1;
use constant HIGH     => 2;

# OPENFLAGS. If we defined the flag to use with Sysopen here this gives
# us an optimisation when many temporary files are requested

my $OPENFLAGS = O_CREAT | O_EXCL | O_RDWR;
my $LOCKFLAG;

unless ($^O eq 'MacOS') {
  for my $oflag (qw/ NOFOLLOW BINARY LARGEFILE NOINHERIT /) {
    my ($bit, $func) = (0, "Fcntl::O_" . $oflag);
    no strict 'refs';
    $OPENFLAGS |= $bit if eval {
      # Make sure that redefined die handlers do not cause problems
      # e.g. CGI::Carp
      local $SIG{__DIE__} = sub {};
      local $SIG{__WARN__} = sub {};
      $bit = &$func();
      1;
    };
  }
  # Special case O_EXLOCK
  $LOCKFLAG = eval {
    local $SIG{__DIE__} = sub {};
    local $SIG{__WARN__} = sub {};
    &Fcntl::O_EXLOCK();
  };
}

# On some systems the O_TEMPORARY flag can be used to tell the OS
# to automatically remove the file when it is closed. This is fine
# in most cases but not if tempfile is called with UNLINK=>0 and
# the filename is requested -- in the case where the filename is to
# be passed to another routine. This happens on windows. We overcome
# this by using a second open flags variable

my $OPENTEMPFLAGS = $OPENFLAGS;
unless ($^O eq 'MacOS') {
  for my $oflag (qw/ TEMPORARY /) {
    my ($bit, $func) = (0, "Fcntl::O_" . $oflag);
    local($@);
    no strict 'refs';
    $OPENTEMPFLAGS |= $bit if eval {
      # Make sure that redefined die handlers do not cause problems
      # e.g. CGI::Carp
      local $SIG{__DIE__} = sub {};
      local $SIG{__WARN__} = sub {};
      $bit = &$func();
      1;
    };
  }
}

# Private hash tracking which files have been created by each process id via the OO interface
my %FILES_CREATED_BY_OBJECT;

# INTERNAL ROUTINES - not to be used outside of package

# Generic routine for getting a temporary filename
# modelled on OpenBSD _gettemp() in mktemp.c

# The template must contain X's that are to be replaced
# with the random values

#  Arguments:

#  TEMPLATE   - string containing the XXXXX's that is converted
#           to a random filename and opened if required

# Optionally, a hash can also be supplied containing specific options
#   "open" => if true open the temp file, else just return the name
#             default is 0
#   "mkdir"=> if true, we are creating a temp directory rather than tempfile
#             default is 0
#   "suffixlen" => number of characters at end of PATH to be ignored.
#                  default is 0.
#   "unlink_on_close" => indicates that, if possible,  the OS should remove
#                        the file as soon as it is closed. Usually indicates
#                        use of the O_TEMPORARY flag to sysopen.
#                        Usually irrelevant on unix
#   "use_exlock" => Indicates that O_EXLOCK should be used. Default is false.
#   "file_permissions" => file permissions for sysopen(). Default is 0600.

# Optionally a reference to a scalar can be passed into the function
# On error this will be used to store the reason for the error
#   "ErrStr"  => \$errstr

# "open" and "mkdir" can not both be true
# "unlink_on_close" is not used when "mkdir" is true.

# The default options are equivalent to mktemp().

# Returns:
#   filehandle - open file handle (if called with doopen=1, else undef)
#   temp name  - name of the temp file or directory

# For example:
#   ($fh, $name) = _gettemp($template, "open" => 1);

# for the current version, failures are associated with
# stored in an error string and returned to give the reason whilst debugging
# This routine is not called by any external function
sub _gettemp {

  croak 'Usage: ($fh, $name) = _gettemp($template, OPTIONS);'
    unless scalar(@_) >= 1;

  # the internal error string - expect it to be overridden
  # Need this in case the caller decides not to supply us a value
  # need an anonymous scalar
  my $tempErrStr;

  # Default options
  my %options = (
                 "open"             => 0,
                 "mkdir"            => 0,
                 "suffixlen"        => 0,
                 "unlink_on_close"  => 0,
                 "use_exlock"       => 0,
                 "ErrStr"           => \$tempErrStr,
                 "file_permissions" => undef,
                );

  # Read the template
  my $template = shift;
  if (ref($template)) {
    # Use a warning here since we have not yet merged ErrStr
    carp "File::Temp::_gettemp: template must not be a reference";
    return ();
  }

  # Check that the number of entries on stack are even
  if (scalar(@_) % 2 != 0) {
    # Use a warning here since we have not yet merged ErrStr
    carp "File::Temp::_gettemp: Must have even number of options";
    return ();
  }

  # Read the options and merge with defaults
  %options = (%options, @_)  if @_;

  # Make sure the error string is set to undef
  ${$options{ErrStr}} = undef;

  # Can not open the file and make a directory in a single call
  if ($options{"open"} && $options{"mkdir"}) {
    ${$options{ErrStr}} = "doopen and domkdir can not both be true\n";
    return ();
  }

  # Find the start of the end of the  Xs (position of last X)
  # Substr starts from 0
  my $start = length($template) - 1 - $options{"suffixlen"};

  # Check that we have at least MINX x X (e.g. 'XXXX") at the end of the string
  # (taking suffixlen into account). Any fewer is insecure.

  # Do it using substr - no reason to use a pattern match since
  # we know where we are looking and what we are looking for

  if (substr($template, $start - MINX + 1, MINX) ne 'X' x MINX) {
    ${$options{ErrStr}} = "The template must end with at least ".
      MINX . " 'X' characters\n";
    return ();
  }

  # Replace all the X at the end of the substring with a
  # random character or just all the XX at the end of a full string.
  # Do it as an if, since the suffix adjusts which section to replace
  # and suffixlen=0 returns nothing if used in the substr directly
  # and generate a full path from the template

  my $path = _replace_XX($template, $options{"suffixlen"});


  # Split the path into constituent parts - eventually we need to check
  # whether the directory exists
  # We need to know whether we are making a temp directory
  # or a tempfile

  my ($volume, $directories, $file);
  my $parent;                   # parent directory
  if ($options{"mkdir"}) {
    # There is no filename at the end
    ($volume, $directories, $file) = File::Spec->splitpath( $path, 1);

    # The parent is then $directories without the last directory
    # Split the directory and put it back together again
    my @dirs = File::Spec->splitdir($directories);

    # If @dirs only has one entry (i.e. the directory template) that means
    # we are in the current directory
    if ($#dirs == 0) {
      $parent = File::Spec->curdir;
    } else {

      if ($^O eq 'VMS') {     # need volume to avoid relative dir spec
        $parent = File::Spec->catdir($volume, @dirs[0..$#dirs-1]);
        $parent = 'sys$disk:[]' if $parent eq '';
      } else {

        # Put it back together without the last one
        $parent = File::Spec->catdir(@dirs[0..$#dirs-1]);

        # ...and attach the volume (no filename)
        $parent = File::Spec->catpath($volume, $parent, '');
      }

    }

  } else {

    # Get rid of the last filename (use File::Basename for this?)
    ($volume, $directories, $file) = File::Spec->splitpath( $path );

    # Join up without the file part
    $parent = File::Spec->catpath($volume,$directories,'');

    # If $parent is empty replace with curdir
    $parent = File::Spec->curdir
      unless $directories ne '';

  }

  # Check that the parent directories exist
  # Do this even for the case where we are simply returning a name
  # not a file -- no point returning a name that includes a directory
  # that does not exist or is not writable

  unless (-e $parent) {
    ${$options{ErrStr}} = "Parent directory ($parent) does not exist";
    return ();
  }
  unless (-d $parent) {
    ${$options{ErrStr}} = "Parent directory ($parent) is not a directory";
    return ();
  }

  # Check the stickiness of the directory and chown giveaway if required
  # If the directory is world writable the sticky bit
  # must be set

  if (File::Temp->safe_level == MEDIUM) {
    my $safeerr;
    unless (_is_safe($parent,\$safeerr)) {
      ${$options{ErrStr}} = "Parent directory ($parent) is not safe ($safeerr)";
      return ();
    }
  } elsif (File::Temp->safe_level == HIGH) {
    my $safeerr;
    unless (_is_verysafe($parent, \$safeerr)) {
      ${$options{ErrStr}} = "Parent directory ($parent) is not safe ($safeerr)";
      return ();
    }
  }

  my $perms = $options{file_permissions};
  my $has_perms = defined $perms;
  $perms = 0600 unless $has_perms;

  # Now try MAX_TRIES time to open the file
  for (my $i = 0; $i < MAX_TRIES; $i++) {

    # Try to open the file if requested
    if ($options{"open"}) {
      my $fh;

      # If we are running before perl5.6.0 we can not auto-vivify
      if ($] < 5.006) {
        $fh = &Symbol::gensym;
      }

      # Try to make sure this will be marked close-on-exec
      # XXX: Win32 doesn't respect this, nor the proper fcntl,
      #      but may have O_NOINHERIT. This may or may not be in Fcntl.
      local $^F = 2;

      # Attempt to open the file
      my $open_success = undef;
      if ( $^O eq 'VMS' and $options{"unlink_on_close"} && !$KEEP_ALL) {
        # make it auto delete on close by setting FAB$V_DLT bit
        $fh = VMS::Stdio::vmssysopen($path, $OPENFLAGS, $perms, 'fop=dlt');
        $open_success = $fh;
      } else {
        my $flags = ( ($options{"unlink_on_close"} && !$KEEP_ALL) ?
                      $OPENTEMPFLAGS :
                      $OPENFLAGS );
        $flags |= $LOCKFLAG if (defined $LOCKFLAG && $options{use_exlock});
        $open_success = sysopen($fh, $path, $flags, $perms);
      }
      if ( $open_success ) {

        # in case of odd umask force rw
        chmod($perms, $path) unless $has_perms;

        # Opened successfully - return file handle and name
        return ($fh, $path);

      } else {

        # Error opening file - abort with error
        # if the reason was anything but EEXIST
        unless ($!{EEXIST}) {
          ${$options{ErrStr}} = "Could not create temp file $path: $!";
          return ();
        }

        # Loop round for another try

      }
    } elsif ($options{"mkdir"}) {

      # Open the temp directory
      if (mkdir( $path, 0700)) {
        # in case of odd umask
        chmod(0700, $path);

        return undef, $path;
      } else {

        # Abort with error if the reason for failure was anything
        # except EEXIST
        unless ($!{EEXIST}) {
          ${$options{ErrStr}} = "Could not create directory $path: $!";
          return ();
        }

        # Loop round for another try

      }

    } else {

      # Return true if the file can not be found
      # Directory has been checked previously

      return (undef, $path) unless -e $path;

      # Try again until MAX_TRIES

    }

    # Did not successfully open the tempfile/dir
    # so try again with a different set of random letters
    # No point in trying to increment unless we have only
    # 1 X say and the randomness could come up with the same
    # file MAX_TRIES in a row.

    # Store current attempt - in principle this implies that the
    # 3rd time around the open attempt that the first temp file
    # name could be generated again. Probably should store each
    # attempt and make sure that none are repeated

    my $original = $path;
    my $counter = 0;            # Stop infinite loop
    my $MAX_GUESS = 50;

    do {

      # Generate new name from original template
      $path = _replace_XX($template, $options{"suffixlen"});

      $counter++;

    } until ($path ne $original || $counter > $MAX_GUESS);

    # Check for out of control looping
    if ($counter > $MAX_GUESS) {
      ${$options{ErrStr}} = "Tried to get a new temp name different to the previous value $MAX_GUESS times.\nSomething wrong with template?? ($template)";
      return ();
    }

  }

  # If we get here, we have run out of tries
  ${ $options{ErrStr} } = "Have exceeded the maximum number of attempts ("
    . MAX_TRIES . ") to open temp file/dir";

  return ();

}

# Internal routine to replace the XXXX... with random characters
# This has to be done by _gettemp() every time it fails to
# open a temp file/dir

# Arguments:  $template (the template with XXX),
#             $ignore   (number of characters at end to ignore)

# Returns:    modified template

sub _replace_XX {

  croak 'Usage: _replace_XX($template, $ignore)'
    unless scalar(@_) == 2;

  my ($path, $ignore) = @_;

  # Do it as an if, since the suffix adjusts which section to replace
  # and suffixlen=0 returns nothing if used in the substr directly
  # Alternatively, could simply set $ignore to length($path)-1
  # Don't want to always use substr when not required though.
  my $end = ( $] >= 5.006 ? "\\z" : "\\Z" );

  if ($ignore) {
    substr($path, 0, - $ignore) =~ s/X(?=X*$end)/$CHARS[ int( rand( @CHARS ) ) ]/ge;
  } else {
    $path =~ s/X(?=X*$end)/$CHARS[ int( rand( @CHARS ) ) ]/ge;
  }
  return $path;
}

# Internal routine to force a temp file to be writable after
# it is created so that we can unlink it. Windows seems to occasionally
# force a file to be readonly when written to certain temp locations
sub _force_writable {
  my $file = shift;
  chmod 0600, $file;
}


# internal routine to check to see if the directory is safe
# First checks to see if the directory is not owned by the
# current user or root. Then checks to see if anyone else
# can write to the directory and if so, checks to see if
# it has the sticky bit set

# Will not work on systems that do not support sticky bit

#Args:  directory path to check
#       Optionally: reference to scalar to contain error message
# Returns true if the path is safe and false otherwise.
# Returns undef if can not even run stat() on the path

# This routine based on version written by Tom Christiansen

# Presumably, by the time we actually attempt to create the
# file or directory in this directory, it may not be safe
# anymore... Have to run _is_safe directly after the open.

sub _is_safe {

  my $path = shift;
  my $err_ref = shift;

  # Stat path
  my @info = stat($path);
  unless (scalar(@info)) {
    $$err_ref = "stat(path) returned no values";
    return 0;
  }
  ;
  return 1 if $^O eq 'VMS';     # owner delete control at file level

  # Check to see whether owner is neither superuser (or a system uid) nor me
  # Use the effective uid from the $> variable
  # UID is in [4]
  if ($info[4] > File::Temp->top_system_uid() && $info[4] != $>) {

    Carp::cluck(sprintf "uid=$info[4] topuid=%s euid=$> path='$path'",
                File::Temp->top_system_uid());

    $$err_ref = "Directory owned neither by root nor the current user"
      if ref($err_ref);
    return 0;
  }

  # check whether group or other can write file
  # use 066 to detect either reading or writing
  # use 022 to check writability
  # Do it with S_IWOTH and S_IWGRP for portability (maybe)
  # mode is in info[2]
  if (($info[2] & &Fcntl::S_IWGRP) ||  # Is group writable?
      ($info[2] & &Fcntl::S_IWOTH) ) { # Is world writable?
    # Must be a directory
    unless (-d $path) {
      $$err_ref = "Path ($path) is not a directory"
        if ref($err_ref);
      return 0;
    }
    # Must have sticky bit set
    unless (-k $path) {
      $$err_ref = "Sticky bit not set on $path when dir is group|world writable"
        if ref($err_ref);
      return 0;
    }
  }

  return 1;
}

# Internal routine to check whether a directory is safe
# for temp files. Safer than _is_safe since it checks for
# the possibility of chown giveaway and if that is a possibility
# checks each directory in the path to see if it is safe (with _is_safe)

# If _PC_CHOWN_RESTRICTED is not set, does the full test of each
# directory anyway.

# Takes optional second arg as scalar ref to error reason

sub _is_verysafe {

  # Need POSIX - but only want to bother if really necessary due to overhead
  require POSIX;

  my $path = shift;
  print "_is_verysafe testing $path\n" if $DEBUG;
  return 1 if $^O eq 'VMS';     # owner delete control at file level

  my $err_ref = shift;

  # Should Get the value of _PC_CHOWN_RESTRICTED if it is defined
  # and If it is not there do the extensive test
  local($@);
  my $chown_restricted;
  $chown_restricted = &POSIX::_PC_CHOWN_RESTRICTED()
    if eval { &POSIX::_PC_CHOWN_RESTRICTED(); 1};

  # If chown_resticted is set to some value we should test it
  if (defined $chown_restricted) {

    # Return if the current directory is safe
    return _is_safe($path,$err_ref) if POSIX::sysconf( $chown_restricted );

  }

  # To reach this point either, the _PC_CHOWN_RESTRICTED symbol
  # was not available or the symbol was there but chown giveaway
  # is allowed. Either way, we now have to test the entire tree for
  # safety.

  # Convert path to an absolute directory if required
  unless (File::Spec->file_name_is_absolute($path)) {
    $path = File::Spec->rel2abs($path);
  }

  # Split directory into components - assume no file
  my ($volume, $directories, undef) = File::Spec->splitpath( $path, 1);

  # Slightly less efficient than having a function in File::Spec
  # to chop off the end of a directory or even a function that
  # can handle ../ in a directory tree
  # Sometimes splitdir() returns a blank at the end
  # so we will probably check the bottom directory twice in some cases
  my @dirs = File::Spec->splitdir($directories);

  # Concatenate one less directory each time around
  foreach my $pos (0.. $#dirs) {
    # Get a directory name
    my $dir = File::Spec->catpath($volume,
                                  File::Spec->catdir(@dirs[0.. $#dirs - $pos]),
                                  ''
                                 );

    print "TESTING DIR $dir\n" if $DEBUG;

    # Check the directory
    return 0 unless _is_safe($dir,$err_ref);

  }

  return 1;
}



# internal routine to determine whether unlink works on this
# platform for files that are currently open.
# Returns true if we can, false otherwise.

# Currently WinNT, OS/2 and VMS can not unlink an opened file
# On VMS this is because the O_EXCL flag is used to open the
# temporary file. Currently I do not know enough about the issues
# on VMS to decide whether O_EXCL is a requirement.

sub _can_unlink_opened_file {

  if (grep $^O eq $_, qw/MSWin32 os2 VMS dos MacOS haiku/) {
    return 0;
  } else {
    return 1;
  }

}

# internal routine to decide which security levels are allowed
# see safe_level() for more information on this

# Controls whether the supplied security level is allowed

#   $cando = _can_do_level( $level )

sub _can_do_level {

  # Get security level
  my $level = shift;

  # Always have to be able to do STANDARD
  return 1 if $level == STANDARD;

  # Currently, the systems that can do HIGH or MEDIUM are identical
  if ( $^O eq 'MSWin32' || $^O eq 'os2' || $^O eq 'cygwin' || $^O eq 'dos' || $^O eq 'MacOS' || $^O eq 'mpeix') {
    return 0;
  } else {
    return 1;
  }

}

# This routine sets up a deferred unlinking of a specified
# filename and filehandle. It is used in the following cases:
#  - Called by unlink0 if an opened file can not be unlinked
#  - Called by tempfile() if files are to be removed on shutdown
#  - Called by tempdir() if directories are to be removed on shutdown

# Arguments:
#   _deferred_unlink( $fh, $fname, $isdir );
#
#   - filehandle (so that it can be explicitly closed if open
#   - filename   (the thing we want to remove)
#   - isdir      (flag to indicate that we are being given a directory)
#                 [and hence no filehandle]

# Status is not referred to since all the magic is done with an END block

{
  # Will set up two lexical variables to contain all the files to be
  # removed. One array for files, another for directories They will
  # only exist in this block.

  #  This means we only have to set up a single END block to remove
  #  all files. 

  # in order to prevent child processes inadvertently deleting the parent
  # temp files we use a hash to store the temp files and directories
  # created by a particular process id.

  # %files_to_unlink contains values that are references to an array of
  # array references containing the filehandle and filename associated with
  # the temp file.
  my (%files_to_unlink, %dirs_to_unlink);

  # Set up an end block to use these arrays
  END {
    local($., $@, $!, $^E, $?);
    cleanup(at_exit => 1);
  }

  # Cleanup function. Always triggered on END (with at_exit => 1) but
  # can be invoked manually.
  sub cleanup {
    my %h = @_;
    my $at_exit = delete $h{at_exit};
    $at_exit = 0 if not defined $at_exit;
    { my @k = sort keys %h; die "unrecognized parameters: @k" if @k }

    if (!$KEEP_ALL) {
      # Files
      my @files = (exists $files_to_unlink{$$} ?
                   @{ $files_to_unlink{$$} } : () );
      foreach my $file (@files) {
        # close the filehandle without checking its state
        # in order to make real sure that this is closed
        # if its already closed then I don't care about the answer
        # probably a better way to do this
        close($file->[0]);      # file handle is [0]

        if (-f $file->[1]) {       # file name is [1]
          _force_writable( $file->[1] ); # for windows
          unlink $file->[1] or warn "Error removing ".$file->[1];
        }
      }
      # Dirs
      my @dirs = (exists $dirs_to_unlink{$$} ?
                  @{ $dirs_to_unlink{$$} } : () );
      my ($cwd, $cwd_to_remove);
      foreach my $dir (@dirs) {
        if (-d $dir) {
          # Some versions of rmtree will abort if you attempt to remove
          # the directory you are sitting in. For automatic cleanup
          # at program exit, we avoid this by chdir()ing out of the way
          # first. If not at program exit, it's best not to mess with the
          # current directory, so just let it fail with a warning.
          if ($at_exit) {
            $cwd = Cwd::abs_path(File::Spec->curdir) if not defined $cwd;
            my $abs = Cwd::abs_path($dir);
            if ($abs eq $cwd) {
              $cwd_to_remove = $dir;
              next;
            }
          }
          eval { rmtree($dir, $DEBUG, 0); };
          warn $@ if ($@ && $^W);
        }
      }

      if (defined $cwd_to_remove) {
        # We do need to clean up the current directory, and everything
        # else is done, so get out of there and remove it.
        chdir $cwd_to_remove or die "cannot chdir to $cwd_to_remove: $!";
        my $updir = File::Spec->updir;
        chdir $updir or die "cannot chdir to $updir: $!";
        eval { rmtree($cwd_to_remove, $DEBUG, 0); };
        warn $@ if ($@ && $^W);
      }

      # clear the arrays
      @{ $files_to_unlink{$$} } = ()
        if exists $files_to_unlink{$$};
      @{ $dirs_to_unlink{$$} } = ()
        if exists $dirs_to_unlink{$$};
    }
  }


  # This is the sub called to register a file for deferred unlinking
  # This could simply store the input parameters and defer everything
  # until the END block. For now we do a bit of checking at this
  # point in order to make sure that (1) we have a file/dir to delete
  # and (2) we have been called with the correct arguments.
  sub _deferred_unlink {

    croak 'Usage:  _deferred_unlink($fh, $fname, $isdir)'
      unless scalar(@_) == 3;

    my ($fh, $fname, $isdir) = @_;

    warn "Setting up deferred removal of $fname\n"
      if $DEBUG;

    # make sure we save the absolute path for later cleanup
    # OK to untaint because we only ever use this internally
    # as a file path, never interpolating into the shell
    $fname = Cwd::abs_path($fname);
    ($fname) = $fname =~ /^(.*)$/;

    # If we have a directory, check that it is a directory
    if ($isdir) {

      if (-d $fname) {

        # Directory exists so store it
        # first on VMS turn []foo into [.foo] for rmtree
        $fname = VMS::Filespec::vmspath($fname) if $^O eq 'VMS';
        $dirs_to_unlink{$$} = [] 
          unless exists $dirs_to_unlink{$$};
        push (@{ $dirs_to_unlink{$$} }, $fname);

      } else {
        carp "Request to remove directory $fname could not be completed since it does not exist!\n" if $^W;
      }

    } else {

      if (-f $fname) {

        # file exists so store handle and name for later removal
        $files_to_unlink{$$} = []
          unless exists $files_to_unlink{$$};
        push(@{ $files_to_unlink{$$} }, [$fh, $fname]);

      } else {
        carp "Request to remove file $fname could not be completed since it is not there!\n" if $^W;
      }

    }

  }


}

# normalize argument keys to upper case and do consistent handling
# of leading template vs TEMPLATE
sub _parse_args {
  my $leading_template = (scalar(@_) % 2 == 1 ? shift(@_) : '' );
  my %args = @_;
  %args = map +(uc($_) => $args{$_}), keys %args;

  # template (store it in an array so that it will
  # disappear from the arg list of tempfile)
  my @template = (
    exists $args{TEMPLATE}  ? $args{TEMPLATE} :
    $leading_template       ? $leading_template : ()
  );
  delete $args{TEMPLATE};

  return( \@template, \%args );
}

#pod =head1 OBJECT-ORIENTED INTERFACE
#pod
#pod This is the primary interface for interacting with
#pod C<File::Temp>. Using the OO interface a temporary file can be created
#pod when the object is constructed and the file can be removed when the
#pod object is no longer required.
#pod
#pod Note that there is no method to obtain the filehandle from the
#pod C<File::Temp> object. The object itself acts as a filehandle.  The object
#pod isa C<IO::Handle> and isa C<IO::Seekable> so all those methods are
#pod available.
#pod
#pod Also, the object is configured such that it stringifies to the name of the
#pod temporary file and so can be compared to a filename directly.  It numifies
#pod to the C<refaddr> the same as other handles and so can be compared to other
#pod handles with C<==>.
#pod
#pod     $fh eq $filename       # as a string
#pod     $fh != \*STDOUT        # as a number
#pod
#pod Available since 0.14.
#pod
#pod =over 4
#pod
#pod =item B<new>
#pod
#pod Create a temporary file object.
#pod
#pod   my $tmp = File::Temp->new();
#pod
#pod by default the object is constructed as if C<tempfile>
#pod was called without options, but with the additional behaviour
#pod that the temporary file is removed by the object destructor
#pod if UNLINK is set to true (the default).
#pod
#pod Supported arguments are the same as for C<tempfile>: UNLINK
#pod (defaulting to true), DIR, EXLOCK, PERMS and SUFFIX.
#pod Additionally, the filename
#pod template is specified using the TEMPLATE option. The OPEN option
#pod is not supported (the file is always opened).
#pod
#pod  $tmp = File::Temp->new( TEMPLATE => 'tempXXXXX',
#pod                         DIR => 'mydir',
#pod                         SUFFIX => '.dat');
#pod
#pod Arguments are case insensitive.
#pod
#pod Can call croak() if an error occurs.
#pod
#pod Available since 0.14.
#pod
#pod TEMPLATE available since 0.23
#pod
#pod =cut

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my ($maybe_template, $args) = _parse_args(@_);

  # see if they are unlinking (defaulting to yes)
  my $unlink = (exists $args->{UNLINK} ? $args->{UNLINK} : 1 );
  delete $args->{UNLINK};

  # Protect OPEN
  delete $args->{OPEN};

  # Open the file and retain file handle and file name
  my ($fh, $path) = tempfile( @$maybe_template, %$args );

  print "Tmp: $fh - $path\n" if $DEBUG;

  # Store the filename in the scalar slot
  ${*$fh} = $path;

  # Cache the filename by pid so that the destructor can decide whether to remove it
  $FILES_CREATED_BY_OBJECT{$$}{$path} = 1;

  # Store unlink information in hash slot (plus other constructor info)
  %{*$fh} = %$args;

  # create the object
  bless $fh, $class;

  # final method-based configuration
  $fh->unlink_on_destroy( $unlink );

  return $fh;
}

#pod =item B<newdir>
#pod
#pod Create a temporary directory using an object oriented interface.
#pod
#pod   $dir = File::Temp->newdir();
#pod
#pod By default the directory is deleted when the object goes out of scope.
#pod
#pod Supports the same options as the C<tempdir> function. Note that directories
#pod created with this method default to CLEANUP => 1.
#pod
#pod   $dir = File::Temp->newdir( $template, %options );
#pod
#pod A template may be specified either with a leading template or
#pod with a TEMPLATE argument.
#pod
#pod Available since 0.19.
#pod
#pod TEMPLATE available since 0.23.
#pod
#pod =cut

sub newdir {
  my $self = shift;

  my ($maybe_template, $args) = _parse_args(@_);

  # handle CLEANUP without passing CLEANUP to tempdir
  my $cleanup = (exists $args->{CLEANUP} ? $args->{CLEANUP} : 1 );
  delete $args->{CLEANUP};

  my $tempdir = tempdir( @$maybe_template, %$args);

  # get a safe absolute path for cleanup, just like
  # happens in _deferred_unlink
  my $real_dir = Cwd::abs_path( $tempdir );
  ($real_dir) = $real_dir =~ /^(.*)$/;

  return bless { DIRNAME => $tempdir,
                 REALNAME => $real_dir,
                 CLEANUP => $cleanup,
                 LAUNCHPID => $$,
               }, "File::Temp::Dir";
}

#pod =item B<filename>
#pod
#pod Return the name of the temporary file associated with this object
#pod (if the object was created using the "new" constructor).
#pod
#pod   $filename = $tmp->filename;
#pod
#pod This method is called automatically when the object is used as
#pod a string.
#pod
#pod Current API available since 0.14
#pod
#pod =cut

sub filename {
  my $self = shift;
  return ${*$self};
}

sub STRINGIFY {
  my $self = shift;
  return $self->filename;
}

# For reference, can't use '0+'=>\&Scalar::Util::refaddr directly because
# refaddr() demands one parameter only, whereas overload.pm calls with three
# even for unary operations like '0+'.
sub NUMIFY {
  return refaddr($_[0]);
}

#pod =item B<dirname>
#pod
#pod Return the name of the temporary directory associated with this
#pod object (if the object was created using the "newdir" constructor).
#pod
#pod   $dirname = $tmpdir->dirname;
#pod
#pod This method is called automatically when the object is used in string context.
#pod
#pod =item B<unlink_on_destroy>
#pod
#pod Control whether the file is unlinked when the object goes out of scope.
#pod The file is removed if this value is true and $KEEP_ALL is not.
#pod
#pod  $fh->unlink_on_destroy( 1 );
#pod
#pod Default is for the file to be removed.
#pod
#pod Current API available since 0.15
#pod
#pod =cut

sub unlink_on_destroy {
  my $self = shift;
  if (@_) {
    ${*$self}{UNLINK} = shift;
  }
  return ${*$self}{UNLINK};
}

#pod =item B<DESTROY>
#pod
#pod When the object goes out of scope, the destructor is called. This
#pod destructor will attempt to unlink the file (using L<unlink1|"unlink1">)
#pod if the constructor was called with UNLINK set to 1 (the default state
#pod if UNLINK is not specified).
#pod
#pod No error is given if the unlink fails.
#pod
#pod If the object has been passed to a child process during a fork, the
#pod file will be deleted when the object goes out of scope in the parent.
#pod
#pod For a temporary directory object the directory will be removed unless
#pod the CLEANUP argument was used in the constructor (and set to false) or
#pod C<unlink_on_destroy> was modified after creation.  Note that if a temp
#pod directory is your current directory, it cannot be removed - a warning
#pod will be given in this case.  C<chdir()> out of the directory before
#pod letting the object go out of scope.
#pod
#pod If the global variable $KEEP_ALL is true, the file or directory
#pod will not be removed.
#pod
#pod =cut

sub DESTROY {
  local($., $@, $!, $^E, $?);
  my $self = shift;

  # Make sure we always remove the file from the global hash
  # on destruction. This prevents the hash from growing uncontrollably
  # and post-destruction there is no reason to know about the file.
  my $file = $self->filename;
  my $was_created_by_proc;
  if (exists $FILES_CREATED_BY_OBJECT{$$}{$file}) {
    $was_created_by_proc = 1;
    delete $FILES_CREATED_BY_OBJECT{$$}{$file};
  }

  if (${*$self}{UNLINK} && !$KEEP_ALL) {
    print "# --------->   Unlinking $self\n" if $DEBUG;

    # only delete if this process created it
    return unless $was_created_by_proc;

    # The unlink1 may fail if the file has been closed
    # by the caller. This leaves us with the decision
    # of whether to refuse to remove the file or simply
    # do an unlink without test. Seems to be silly
    # to do this when we are trying to be careful
    # about security
    _force_writable( $file ); # for windows
    unlink1( $self, $file )
      or unlink($file);
  }
}

#pod =back
#pod
#pod =head1 FUNCTIONS
#pod
#pod This section describes the recommended interface for generating
#pod temporary files and directories.
#pod
#pod =over 4
#pod
#pod =item B<tempfile>
#pod
#pod This is the basic function to generate temporary files.
#pod The behaviour of the file can be changed using various options:
#pod
#pod   $fh = tempfile();
#pod   ($fh, $filename) = tempfile();
#pod
#pod Create a temporary file in  the directory specified for temporary
#pod files, as specified by the tmpdir() function in L<File::Spec>.
#pod
#pod   ($fh, $filename) = tempfile($template);
#pod
#pod Create a temporary file in the current directory using the supplied
#pod template.  Trailing `X' characters are replaced with random letters to
#pod generate the filename.  At least four `X' characters must be present
#pod at the end of the template.
#pod
#pod   ($fh, $filename) = tempfile($template, SUFFIX => $suffix)
#pod
#pod Same as previously, except that a suffix is added to the template
#pod after the `X' translation.  Useful for ensuring that a temporary
#pod filename has a particular extension when needed by other applications.
#pod But see the WARNING at the end.
#pod
#pod   ($fh, $filename) = tempfile($template, DIR => $dir);
#pod
#pod Translates the template as before except that a directory name
#pod is specified.
#pod
#pod   ($fh, $filename) = tempfile($template, TMPDIR => 1);
#pod
#pod Equivalent to specifying a DIR of "File::Spec->tmpdir", writing the file
#pod into the same temporary directory as would be used if no template was
#pod specified at all.
#pod
#pod   ($fh, $filename) = tempfile($template, UNLINK => 1);
#pod
#pod Return the filename and filehandle as before except that the file is
#pod automatically removed when the program exits (dependent on
#pod $KEEP_ALL). Default is for the file to be removed if a file handle is
#pod requested and to be kept if the filename is requested. In a scalar
#pod context (where no filename is returned) the file is always deleted
#pod either (depending on the operating system) on exit or when it is
#pod closed (unless $KEEP_ALL is true when the temp file is created).
#pod
#pod Use the object-oriented interface if fine-grained control of when
#pod a file is removed is required.
#pod
#pod If the template is not specified, a template is always
#pod automatically generated. This temporary file is placed in tmpdir()
#pod (L<File::Spec>) unless a directory is specified explicitly with the
#pod DIR option.
#pod
#pod   $fh = tempfile( DIR => $dir );
#pod
#pod If called in scalar context, only the filehandle is returned and the
#pod file will automatically be deleted when closed on operating systems
#pod that support this (see the description of tmpfile() elsewhere in this
#pod document).  This is the preferred mode of operation, as if you only
#pod have a filehandle, you can never create a race condition by fumbling
#pod with the filename. On systems that can not unlink an open file or can
#pod not mark a file as temporary when it is opened (for example, Windows
#pod NT uses the C<O_TEMPORARY> flag) the file is marked for deletion when
#pod the program ends (equivalent to setting UNLINK to 1). The C<UNLINK>
#pod flag is ignored if present.
#pod
#pod   (undef, $filename) = tempfile($template, OPEN => 0);
#pod
#pod This will return the filename based on the template but
#pod will not open this file.  Cannot be used in conjunction with
#pod UNLINK set to true. Default is to always open the file
#pod to protect from possible race conditions. A warning is issued
#pod if warnings are turned on. Consider using the tmpnam()
#pod and mktemp() functions described elsewhere in this document
#pod if opening the file is not required.
#pod
#pod To open the temporary filehandle with O_EXLOCK (open with exclusive
#pod file lock) use C<< EXLOCK=>1 >>. This is supported only by some
#pod operating systems (most notably BSD derived systems). By default
#pod EXLOCK will be false. Former C<File::Temp> versions set EXLOCK to
#pod true, so to be sure to get an unlocked filehandle also with older
#pod versions, explicitly set C<< EXLOCK=>0 >>.
#pod
#pod   ($fh, $filename) = tempfile($template, EXLOCK => 1);
#pod
#pod By default, the temp file is created with 0600 file permissions.
#pod Use C<PERMS> to change this:
#pod
#pod   ($fh, $filename) = tempfile($template, PERMS => 0666);
#pod
#pod Options can be combined as required.
#pod
#pod Will croak() if there is an error.
#pod
#pod Available since 0.05.
#pod
#pod UNLINK flag available since 0.10.
#pod
#pod TMPDIR flag available since 0.19.
#pod
#pod EXLOCK flag available since 0.19.
#pod
#pod PERMS flag available since 0.2310.
#pod
#pod =cut

sub tempfile {
  if ( @_ && $_[0] eq 'File::Temp' ) {
      croak "'tempfile' can't be called as a method";
  }
  # Can not check for argument count since we can have any
  # number of args

  # Default options
  my %options = (
                 "DIR"    => undef, # Directory prefix
                 "SUFFIX" => '',    # Template suffix
                 "UNLINK" => 0,     # Do not unlink file on exit
                 "OPEN"   => 1,     # Open file
                 "TMPDIR" => 0,     # Place tempfile in tempdir if template specified
                 "EXLOCK" => 0,     # Open file with O_EXLOCK
                 "PERMS"  => undef, # File permissions
                );

  # Check to see whether we have an odd or even number of arguments
  my ($maybe_template, $args) = _parse_args(@_);
  my $template = @$maybe_template ? $maybe_template->[0] : undef;

  # Read the options and merge with defaults
  %options = (%options, %$args);

  # First decision is whether or not to open the file
  if (! $options{"OPEN"}) {

    warn "tempfile(): temporary filename requested but not opened.\nPossibly unsafe, consider using tempfile() with OPEN set to true\n"
      if $^W;

  }

  if ($options{"DIR"} and $^O eq 'VMS') {

    # on VMS turn []foo into [.foo] for concatenation
    $options{"DIR"} = VMS::Filespec::vmspath($options{"DIR"});
  }

  # Construct the template

  # Have a choice of trying to work around the mkstemp/mktemp/tmpnam etc
  # functions or simply constructing a template and using _gettemp()
  # explicitly. Go for the latter

  # First generate a template if not defined and prefix the directory
  # If no template must prefix the temp directory
  if (defined $template) {
    # End up with current directory if neither DIR not TMPDIR are set
    if ($options{"DIR"}) {

      $template = File::Spec->catfile($options{"DIR"}, $template);

    } elsif ($options{TMPDIR}) {

      $template = File::Spec->catfile(_wrap_file_spec_tmpdir(), $template );

    }

  } else {

    if ($options{"DIR"}) {

      $template = File::Spec->catfile($options{"DIR"}, TEMPXXX);

    } else {

      $template = File::Spec->catfile(_wrap_file_spec_tmpdir(), TEMPXXX);

    }

  }

  # Now add a suffix
  $template .= $options{"SUFFIX"};

  # Determine whether we should tell _gettemp to unlink the file
  # On unix this is irrelevant and can be worked out after the file is
  # opened (simply by unlinking the open filehandle). On Windows or VMS
  # we have to indicate temporary-ness when we open the file. In general
  # we only want a true temporary file if we are returning just the
  # filehandle - if the user wants the filename they probably do not
  # want the file to disappear as soon as they close it (which may be
  # important if they want a child process to use the file)
  # For this reason, tie unlink_on_close to the return context regardless
  # of OS.
  my $unlink_on_close = ( wantarray ? 0 : 1);

  # Create the file
  my ($fh, $path, $errstr);
  croak "Error in tempfile() using template $template: $errstr"
    unless (($fh, $path) = _gettemp($template,
                                    "open"             => $options{OPEN},
                                    "mkdir"            => 0,
                                    "unlink_on_close"  => $unlink_on_close,
                                    "suffixlen"        => length($options{SUFFIX}),
                                    "ErrStr"           => \$errstr,
                                    "use_exlock"       => $options{EXLOCK},
                                    "file_permissions" => $options{PERMS},
                                   ) );

  # Set up an exit handler that can do whatever is right for the
  # system. This removes files at exit when requested explicitly or when
  # system is asked to unlink_on_close but is unable to do so because
  # of OS limitations.
  # The latter should be achieved by using a tied filehandle.
  # Do not check return status since this is all done with END blocks.
  _deferred_unlink($fh, $path, 0) if $options{"UNLINK"};

  # Return
  if (wantarray()) {

    if ($options{'OPEN'}) {
      return ($fh, $path);
    } else {
      return (undef, $path);
    }

  } else {

    # Unlink the file. It is up to unlink0 to decide what to do with
    # this (whether to unlink now or to defer until later)
    unlink0($fh, $path) or croak "Error unlinking file $path using unlink0";

    # Return just the filehandle.
    return $fh;
  }


}

# On Windows under taint mode, File::Spec could suggest "C:\" as a tempdir
# which might not be writable.  If that is the case, we fallback to a
# user directory.  See https://rt.cpan.org/Ticket/Display.html?id=60340

{
  my ($alt_tmpdir, $checked);

  sub _wrap_file_spec_tmpdir {
    return File::Spec->tmpdir unless $^O eq "MSWin32" && ${^TAINT};

    if ( $checked ) {
      return $alt_tmpdir ? $alt_tmpdir : File::Spec->tmpdir;
    }

    # probe what File::Spec gives and find a fallback
    my $xxpath = _replace_XX( "X" x 10, 0 );

    # First, see if File::Spec->tmpdir is writable
    my $tmpdir = File::Spec->tmpdir;
    my $testpath = File::Spec->catdir( $tmpdir, $xxpath );
    if (mkdir( $testpath, 0700) ) {
      $checked = 1;
      rmdir $testpath;
      return $tmpdir;
    }

    # Next, see if CSIDL_LOCAL_APPDATA is writable
    require Win32;
    my $local_app = File::Spec->catdir(
      Win32::GetFolderPath( Win32::CSIDL_LOCAL_APPDATA() ), 'Temp'
    );
    $testpath = File::Spec->catdir( $local_app, $xxpath );
    if ( -e $local_app or mkdir( $local_app, 0700 ) ) {
      if (mkdir( $testpath, 0700) ) {
        $checked = 1;
        rmdir $testpath;
        return $alt_tmpdir = $local_app;
      }
    }

    # Can't find something writable
    croak << "HERE";
Couldn't find a writable temp directory in taint mode. Tried:
  $tmpdir
  $local_app

Try setting and untainting the TMPDIR environment variable.
HERE

  }
}

#pod =item B<tempdir>
#pod
#pod This is the recommended interface for creation of temporary
#pod directories.  By default the directory will not be removed on exit
#pod (that is, it won't be temporary; this behaviour can not be changed
#pod because of issues with backwards compatibility). To enable removal
#pod either use the CLEANUP option which will trigger removal on program
#pod exit, or consider using the "newdir" method in the object interface which
#pod will allow the directory to be cleaned up when the object goes out of
#pod scope.
#pod
#pod The behaviour of the function depends on the arguments:
#pod
#pod   $tempdir = tempdir();
#pod
#pod Create a directory in tmpdir() (see L<File::Spec|File::Spec>).
#pod
#pod   $tempdir = tempdir( $template );
#pod
#pod Create a directory from the supplied template. This template is
#pod similar to that described for tempfile(). `X' characters at the end
#pod of the template are replaced with random letters to construct the
#pod directory name. At least four `X' characters must be in the template.
#pod
#pod   $tempdir = tempdir ( DIR => $dir );
#pod
#pod Specifies the directory to use for the temporary directory.
#pod The temporary directory name is derived from an internal template.
#pod
#pod   $tempdir = tempdir ( $template, DIR => $dir );
#pod
#pod Prepend the supplied directory name to the template. The template
#pod should not include parent directory specifications itself. Any parent
#pod directory specifications are removed from the template before
#pod prepending the supplied directory.
#pod
#pod   $tempdir = tempdir ( $template, TMPDIR => 1 );
#pod
#pod Using the supplied template, create the temporary directory in
#pod a standard location for temporary files. Equivalent to doing
#pod
#pod   $tempdir = tempdir ( $template, DIR => File::Spec->tmpdir);
#pod
#pod but shorter. Parent directory specifications are stripped from the
#pod template itself. The C<TMPDIR> option is ignored if C<DIR> is set
#pod explicitly.  Additionally, C<TMPDIR> is implied if neither a template
#pod nor a directory are supplied.
#pod
#pod   $tempdir = tempdir( $template, CLEANUP => 1);
#pod
#pod Create a temporary directory using the supplied template, but
#pod attempt to remove it (and all files inside it) when the program
#pod exits. Note that an attempt will be made to remove all files from
#pod the directory even if they were not created by this module (otherwise
#pod why ask to clean it up?). The directory removal is made with
#pod the rmtree() function from the L<File::Path|File::Path> module.
#pod Of course, if the template is not specified, the temporary directory
#pod will be created in tmpdir() and will also be removed at program exit.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

# '

sub tempdir  {
  if ( @_ && $_[0] eq 'File::Temp' ) {
      croak "'tempdir' can't be called as a method";
  }

  # Can not check for argument count since we can have any
  # number of args

  # Default options
  my %options = (
                 "CLEANUP"    => 0, # Remove directory on exit
                 "DIR"        => '', # Root directory
                 "TMPDIR"     => 0,  # Use tempdir with template
                );

  # Check to see whether we have an odd or even number of arguments
  my ($maybe_template, $args) = _parse_args(@_);
  my $template = @$maybe_template ? $maybe_template->[0] : undef;

  # Read the options and merge with defaults
  %options = (%options, %$args);

  # Modify or generate the template

  # Deal with the DIR and TMPDIR options
  if (defined $template) {

    # Need to strip directory path if using DIR or TMPDIR
    if ($options{'TMPDIR'} || $options{'DIR'}) {

      # Strip parent directory from the filename
      #
      # There is no filename at the end
      $template = VMS::Filespec::vmspath($template) if $^O eq 'VMS';
      my ($volume, $directories, undef) = File::Spec->splitpath( $template, 1);

      # Last directory is then our template
      $template = (File::Spec->splitdir($directories))[-1];

      # Prepend the supplied directory or temp dir
      if ($options{"DIR"}) {

        $template = File::Spec->catdir($options{"DIR"}, $template);

      } elsif ($options{TMPDIR}) {

        # Prepend tmpdir
        $template = File::Spec->catdir(_wrap_file_spec_tmpdir(), $template);

      }

    }

  } else {

    if ($options{"DIR"}) {

      $template = File::Spec->catdir($options{"DIR"}, TEMPXXX);

    } else {

      $template = File::Spec->catdir(_wrap_file_spec_tmpdir(), TEMPXXX);

    }

  }

  # Create the directory
  my $tempdir;
  my $suffixlen = 0;
  if ($^O eq 'VMS') {           # dir names can end in delimiters
    $template =~ m/([\.\]:>]+)$/;
    $suffixlen = length($1);
  }
  if ( ($^O eq 'MacOS') && (substr($template, -1) eq ':') ) {
    # dir name has a trailing ':'
    ++$suffixlen;
  }

  my $errstr;
  croak "Error in tempdir() using $template: $errstr"
    unless ((undef, $tempdir) = _gettemp($template,
                                         "open" => 0,
                                         "mkdir"=> 1 ,
                                         "suffixlen" => $suffixlen,
                                         "ErrStr" => \$errstr,
                                        ) );

  # Install exit handler; must be dynamic to get lexical
  if ( $options{'CLEANUP'} && -d $tempdir) {
    _deferred_unlink(undef, $tempdir, 1);
  }

  # Return the dir name
  return $tempdir;

}

#pod =back
#pod
#pod =head1 MKTEMP FUNCTIONS
#pod
#pod The following functions are Perl implementations of the
#pod mktemp() family of temp file generation system calls.
#pod
#pod =over 4
#pod
#pod =item B<mkstemp>
#pod
#pod Given a template, returns a filehandle to the temporary file and the name
#pod of the file.
#pod
#pod   ($fh, $name) = mkstemp( $template );
#pod
#pod In scalar context, just the filehandle is returned.
#pod
#pod The template may be any filename with some number of X's appended
#pod to it, for example F</tmp/temp.XXXX>. The trailing X's are replaced
#pod with unique alphanumeric combinations.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut



sub mkstemp {

  croak "Usage: mkstemp(template)"
    if scalar(@_) != 1;

  my $template = shift;

  my ($fh, $path, $errstr);
  croak "Error in mkstemp using $template: $errstr"
    unless (($fh, $path) = _gettemp($template,
                                    "open" => 1,
                                    "mkdir"=> 0 ,
                                    "suffixlen" => 0,
                                    "ErrStr" => \$errstr,
                                   ) );

  if (wantarray()) {
    return ($fh, $path);
  } else {
    return $fh;
  }

}


#pod =item B<mkstemps>
#pod
#pod Similar to mkstemp(), except that an extra argument can be supplied
#pod with a suffix to be appended to the template.
#pod
#pod   ($fh, $name) = mkstemps( $template, $suffix );
#pod
#pod For example a template of C<testXXXXXX> and suffix of C<.dat>
#pod would generate a file similar to F<testhGji_w.dat>.
#pod
#pod Returns just the filehandle alone when called in scalar context.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

sub mkstemps {

  croak "Usage: mkstemps(template, suffix)"
    if scalar(@_) != 2;


  my $template = shift;
  my $suffix   = shift;

  $template .= $suffix;

  my ($fh, $path, $errstr);
  croak "Error in mkstemps using $template: $errstr"
    unless (($fh, $path) = _gettemp($template,
                                    "open" => 1,
                                    "mkdir"=> 0 ,
                                    "suffixlen" => length($suffix),
                                    "ErrStr" => \$errstr,
                                   ) );

  if (wantarray()) {
    return ($fh, $path);
  } else {
    return $fh;
  }

}

#pod =item B<mkdtemp>
#pod
#pod Create a directory from a template. The template must end in
#pod X's that are replaced by the routine.
#pod
#pod   $tmpdir_name = mkdtemp($template);
#pod
#pod Returns the name of the temporary directory created.
#pod
#pod Directory must be removed by the caller.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

#' # for emacs

sub mkdtemp {

  croak "Usage: mkdtemp(template)"
    if scalar(@_) != 1;

  my $template = shift;
  my $suffixlen = 0;
  if ($^O eq 'VMS') {           # dir names can end in delimiters
    $template =~ m/([\.\]:>]+)$/;
    $suffixlen = length($1);
  }
  if ( ($^O eq 'MacOS') && (substr($template, -1) eq ':') ) {
    # dir name has a trailing ':'
    ++$suffixlen;
  }
  my ($junk, $tmpdir, $errstr);
  croak "Error creating temp directory from template $template\: $errstr"
    unless (($junk, $tmpdir) = _gettemp($template,
                                        "open" => 0,
                                        "mkdir"=> 1 ,
                                        "suffixlen" => $suffixlen,
                                        "ErrStr" => \$errstr,
                                       ) );

  return $tmpdir;

}

#pod =item B<mktemp>
#pod
#pod Returns a valid temporary filename but does not guarantee
#pod that the file will not be opened by someone else.
#pod
#pod   $unopened_file = mktemp($template);
#pod
#pod Template is the same as that required by mkstemp().
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

sub mktemp {

  croak "Usage: mktemp(template)"
    if scalar(@_) != 1;

  my $template = shift;

  my ($tmpname, $junk, $errstr);
  croak "Error getting name to temp file from template $template: $errstr"
    unless (($junk, $tmpname) = _gettemp($template,
                                         "open" => 0,
                                         "mkdir"=> 0 ,
                                         "suffixlen" => 0,
                                         "ErrStr" => \$errstr,
                                        ) );

  return $tmpname;
}

#pod =back
#pod
#pod =head1 POSIX FUNCTIONS
#pod
#pod This section describes the re-implementation of the tmpnam()
#pod and tmpfile() functions described in L<POSIX>
#pod using the mkstemp() from this module.
#pod
#pod Unlike the L<POSIX|POSIX> implementations, the directory used
#pod for the temporary file is not specified in a system include
#pod file (C<P_tmpdir>) but simply depends on the choice of tmpdir()
#pod returned by L<File::Spec|File::Spec>. On some implementations this
#pod location can be set using the C<TMPDIR> environment variable, which
#pod may not be secure.
#pod If this is a problem, simply use mkstemp() and specify a template.
#pod
#pod =over 4
#pod
#pod =item B<tmpnam>
#pod
#pod When called in scalar context, returns the full name (including path)
#pod of a temporary file (uses mktemp()). The only check is that the file does
#pod not already exist, but there is no guarantee that that condition will
#pod continue to apply.
#pod
#pod   $file = tmpnam();
#pod
#pod When called in list context, a filehandle to the open file and
#pod a filename are returned. This is achieved by calling mkstemp()
#pod after constructing a suitable template.
#pod
#pod   ($fh, $file) = tmpnam();
#pod
#pod If possible, this form should be used to prevent possible
#pod race conditions.
#pod
#pod See L<File::Spec/tmpdir> for information on the choice of temporary
#pod directory for a particular operating system.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

sub tmpnam {

  # Retrieve the temporary directory name
  my $tmpdir = _wrap_file_spec_tmpdir();

  # XXX I don't know under what circumstances this occurs, -- xdg 2016-04-02
  croak "Error temporary directory is not writable"
    if $tmpdir eq '';

  # Use a ten character template and append to tmpdir
  my $template = File::Spec->catfile($tmpdir, TEMPXXX);

  if (wantarray() ) {
    return mkstemp($template);
  } else {
    return mktemp($template);
  }

}

#pod =item B<tmpfile>
#pod
#pod Returns the filehandle of a temporary file.
#pod
#pod   $fh = tmpfile();
#pod
#pod The file is removed when the filehandle is closed or when the program
#pod exits. No access to the filename is provided.
#pod
#pod If the temporary file can not be created undef is returned.
#pod Currently this command will probably not work when the temporary
#pod directory is on an NFS file system.
#pod
#pod Will croak() if there is an error.
#pod
#pod Available since 0.05.
#pod
#pod Returning undef if unable to create file added in 0.12.
#pod
#pod =cut

sub tmpfile {

  # Simply call tmpnam() in a list context
  my ($fh, $file) = tmpnam();

  # Make sure file is removed when filehandle is closed
  # This will fail on NFS
  unlink0($fh, $file)
    or return undef;

  return $fh;

}

#pod =back
#pod
#pod =head1 ADDITIONAL FUNCTIONS
#pod
#pod These functions are provided for backwards compatibility
#pod with common tempfile generation C library functions.
#pod
#pod They are not exported and must be addressed using the full package
#pod name.
#pod
#pod =over 4
#pod
#pod =item B<tempnam>
#pod
#pod Return the name of a temporary file in the specified directory
#pod using a prefix. The file is guaranteed not to exist at the time
#pod the function was called, but such guarantees are good for one
#pod clock tick only.  Always use the proper form of C<sysopen>
#pod with C<O_CREAT | O_EXCL> if you must open such a filename.
#pod
#pod   $filename = File::Temp::tempnam( $dir, $prefix );
#pod
#pod Equivalent to running mktemp() with $dir/$prefixXXXXXXXX
#pod (using unix file convention as an example)
#pod
#pod Because this function uses mktemp(), it can suffer from race conditions.
#pod
#pod Will croak() if there is an error.
#pod
#pod Current API available since 0.05.
#pod
#pod =cut

sub tempnam {

  croak 'Usage tempnam($dir, $prefix)' unless scalar(@_) == 2;

  my ($dir, $prefix) = @_;

  # Add a string to the prefix
  $prefix .= 'XXXXXXXX';

  # Concatenate the directory to the file
  my $template = File::Spec->catfile($dir, $prefix);

  return mktemp($template);

}

#pod =back
#pod
#pod =head1 UTILITY FUNCTIONS
#pod
#pod Useful functions for dealing with the filehandle and filename.
#pod
#pod =over 4
#pod
#pod =item B<unlink0>
#pod
#pod Given an open filehandle and the associated filename, make a safe
#pod unlink. This is achieved by first checking that the filename and
#pod filehandle initially point to the same file and that the number of
#pod links to the file is 1 (all fields returned by stat() are compared).
#pod Then the filename is unlinked and the filehandle checked once again to
#pod verify that the number of links on that file is now 0.  This is the
#pod closest you can come to making sure that the filename unlinked was the
#pod same as the file whose descriptor you hold.
#pod
#pod   unlink0($fh, $path)
#pod      or die "Error unlinking file $path safely";
#pod
#pod Returns false on error but croaks() if there is a security
#pod anomaly. The filehandle is not closed since on some occasions this is
#pod not required.
#pod
#pod On some platforms, for example Windows NT, it is not possible to
#pod unlink an open file (the file must be closed first). On those
#pod platforms, the actual unlinking is deferred until the program ends and
#pod good status is returned. A check is still performed to make sure that
#pod the filehandle and filename are pointing to the same thing (but not at
#pod the time the end block is executed since the deferred removal may not
#pod have access to the filehandle).
#pod
#pod Additionally, on Windows NT not all the fields returned by stat() can
#pod be compared. For example, the C<dev> and C<rdev> fields seem to be
#pod different.  Also, it seems that the size of the file returned by stat()
#pod does not always agree, with C<stat(FH)> being more accurate than
#pod C<stat(filename)>, presumably because of caching issues even when
#pod using autoflush (this is usually overcome by waiting a while after
#pod writing to the tempfile before attempting to C<unlink0> it).
#pod
#pod Finally, on NFS file systems the link count of the file handle does
#pod not always go to zero immediately after unlinking. Currently, this
#pod command is expected to fail on NFS disks.
#pod
#pod This function is disabled if the global variable $KEEP_ALL is true
#pod and an unlink on open file is supported. If the unlink is to be deferred
#pod to the END block, the file is still registered for removal.
#pod
#pod This function should not be called if you are using the object oriented
#pod interface since the it will interfere with the object destructor deleting
#pod the file.
#pod
#pod Available Since 0.05.
#pod
#pod If can not unlink open file, defer removal until later available since 0.06.
#pod
#pod =cut

sub unlink0 {

  croak 'Usage: unlink0(filehandle, filename)'
    unless scalar(@_) == 2;

  # Read args
  my ($fh, $path) = @_;

  cmpstat($fh, $path) or return 0;

  # attempt remove the file (does not work on some platforms)
  if (_can_unlink_opened_file()) {

    # return early (Without unlink) if we have been instructed to retain files.
    return 1 if $KEEP_ALL;

    # XXX: do *not* call this on a directory; possible race
    #      resulting in recursive removal
    croak "unlink0: $path has become a directory!" if -d $path;
    unlink($path) or return 0;

    # Stat the filehandle
    my @fh = stat $fh;

    print "Link count = $fh[3] \n" if $DEBUG;

    # Make sure that the link count is zero
    # - Cygwin provides deferred unlinking, however,
    #   on Win9x the link count remains 1
    # On NFS the link count may still be 1 but we can't know that
    # we are on NFS.  Since we can't be sure, we'll defer it

    return 1 if $fh[3] == 0 || $^O eq 'cygwin';
  }
  # fall-through if we can't unlink now
  _deferred_unlink($fh, $path, 0);
  return 1;
}

#pod =item B<cmpstat>
#pod
#pod Compare C<stat> of filehandle with C<stat> of provided filename.  This
#pod can be used to check that the filename and filehandle initially point
#pod to the same file and that the number of links to the file is 1 (all
#pod fields returned by stat() are compared).
#pod
#pod   cmpstat($fh, $path)
#pod      or die "Error comparing handle with file";
#pod
#pod Returns false if the stat information differs or if the link count is
#pod greater than 1. Calls croak if there is a security anomaly.
#pod
#pod On certain platforms, for example Windows, not all the fields returned by stat()
#pod can be compared. For example, the C<dev> and C<rdev> fields seem to be
#pod different in Windows.  Also, it seems that the size of the file
#pod returned by stat() does not always agree, with C<stat(FH)> being more
#pod accurate than C<stat(filename)>, presumably because of caching issues
#pod even when using autoflush (this is usually overcome by waiting a while
#pod after writing to the tempfile before attempting to C<unlink0> it).
#pod
#pod Not exported by default.
#pod
#pod Current API available since 0.14.
#pod
#pod =cut

sub cmpstat {

  croak 'Usage: cmpstat(filehandle, filename)'
    unless scalar(@_) == 2;

  # Read args
  my ($fh, $path) = @_;

  warn "Comparing stat\n"
    if $DEBUG;

  # Stat the filehandle - which may be closed if someone has manually
  # closed the file. Can not turn off warnings without using $^W
  # unless we upgrade to 5.006 minimum requirement
  my @fh;
  {
    local ($^W) = 0;
    @fh = stat $fh;
  }
  return unless @fh;

  if ($fh[3] > 1 && $^W) {
    carp "unlink0: fstat found too many links; SB=@fh" if $^W;
  }

  # Stat the path
  my @path = stat $path;

  unless (@path) {
    carp "unlink0: $path is gone already" if $^W;
    return;
  }

  # this is no longer a file, but may be a directory, or worse
  unless (-f $path) {
    confess "panic: $path is no longer a file: SB=@fh";
  }

  # Do comparison of each member of the array
  # On WinNT dev and rdev seem to be different
  # depending on whether it is a file or a handle.
  # Cannot simply compare all members of the stat return
  # Select the ones we can use
  my @okstat = (0..$#fh);       # Use all by default
  if ($^O eq 'MSWin32') {
    @okstat = (1,2,3,4,5,7,8,9,10);
  } elsif ($^O eq 'os2') {
    @okstat = (0, 2..$#fh);
  } elsif ($^O eq 'VMS') {      # device and file ID are sufficient
    @okstat = (0, 1);
  } elsif ($^O eq 'dos') {
    @okstat = (0,2..7,11..$#fh);
  } elsif ($^O eq 'mpeix') {
    @okstat = (0..4,8..10);
  }

  # Now compare each entry explicitly by number
  for (@okstat) {
    print "Comparing: $_ : $fh[$_] and $path[$_]\n" if $DEBUG;
    # Use eq rather than == since rdev, blksize, and blocks (6, 11,
    # and 12) will be '' on platforms that do not support them.  This
    # is fine since we are only comparing integers.
    unless ($fh[$_] eq $path[$_]) {
      warn "Did not match $_ element of stat\n" if $DEBUG;
      return 0;
    }
  }

  return 1;
}

#pod =item B<unlink1>
#pod
#pod Similar to C<unlink0> except after file comparison using cmpstat, the
#pod filehandle is closed prior to attempting to unlink the file. This
#pod allows the file to be removed without using an END block, but does
#pod mean that the post-unlink comparison of the filehandle state provided
#pod by C<unlink0> is not available.
#pod
#pod   unlink1($fh, $path)
#pod      or die "Error closing and unlinking file";
#pod
#pod Usually called from the object destructor when using the OO interface.
#pod
#pod Not exported by default.
#pod
#pod This function is disabled if the global variable $KEEP_ALL is true.
#pod
#pod Can call croak() if there is a security anomaly during the stat()
#pod comparison.
#pod
#pod Current API available since 0.14.
#pod
#pod =cut

sub unlink1 {
  croak 'Usage: unlink1(filehandle, filename)'
    unless scalar(@_) == 2;

  # Read args
  my ($fh, $path) = @_;

  cmpstat($fh, $path) or return 0;

  # Close the file
  close( $fh ) or return 0;

  # Make sure the file is writable (for windows)
  _force_writable( $path );

  # return early (without unlink) if we have been instructed to retain files.
  return 1 if $KEEP_ALL;

  # remove the file
  return unlink($path);
}

#pod =item B<cleanup>
#pod
#pod Calling this function will cause any temp files or temp directories
#pod that are registered for removal to be removed. This happens automatically
#pod when the process exits but can be triggered manually if the caller is sure
#pod that none of the temp files are required. This method can be registered as
#pod an Apache callback.
#pod
#pod Note that if a temp directory is your current directory, it cannot be
#pod removed.  C<chdir()> out of the directory first before calling
#pod C<cleanup()>. (For the cleanup at program exit when the CLEANUP flag
#pod is set, this happens automatically.)
#pod
#pod On OSes where temp files are automatically removed when the temp file
#pod is closed, calling this function will have no effect other than to remove
#pod temporary directories (which may include temporary files).
#pod
#pod   File::Temp::cleanup();
#pod
#pod Not exported by default.
#pod
#pod Current API available since 0.15.
#pod
#pod =back
#pod
#pod =head1 PACKAGE VARIABLES
#pod
#pod These functions control the global state of the package.
#pod
#pod =over 4
#pod
#pod =item B<safe_level>
#pod
#pod Controls the lengths to which the module will go to check the safety of the
#pod temporary file or directory before proceeding.
#pod Options are:
#pod
#pod =over 8
#pod
#pod =item STANDARD
#pod
#pod Do the basic security measures to ensure the directory exists and is
#pod writable, that temporary files are opened only if they do not already
#pod exist, and that possible race conditions are avoided.  Finally the
#pod L<unlink0|"unlink0"> function is used to remove files safely.
#pod
#pod =item MEDIUM
#pod
#pod In addition to the STANDARD security, the output directory is checked
#pod to make sure that it is owned either by root or the user running the
#pod program. If the directory is writable by group or by other, it is then
#pod checked to make sure that the sticky bit is set.
#pod
#pod Will not work on platforms that do not support the C<-k> test
#pod for sticky bit.
#pod
#pod =item HIGH
#pod
#pod In addition to the MEDIUM security checks, also check for the
#pod possibility of ``chown() giveaway'' using the L<POSIX|POSIX>
#pod sysconf() function. If this is a possibility, each directory in the
#pod path is checked in turn for safeness, recursively walking back to the
#pod root directory.
#pod
#pod For platforms that do not support the L<POSIX|POSIX>
#pod C<_PC_CHOWN_RESTRICTED> symbol (for example, Windows NT) it is
#pod assumed that ``chown() giveaway'' is possible and the recursive test
#pod is performed.
#pod
#pod =back
#pod
#pod The level can be changed as follows:
#pod
#pod   File::Temp->safe_level( File::Temp::HIGH );
#pod
#pod The level constants are not exported by the module.
#pod
#pod Currently, you must be running at least perl v5.6.0 in order to
#pod run with MEDIUM or HIGH security. This is simply because the
#pod safety tests use functions from L<Fcntl|Fcntl> that are not
#pod available in older versions of perl. The problem is that the version
#pod number for Fcntl is the same in perl 5.6.0 and in 5.005_03 even though
#pod they are different versions.
#pod
#pod On systems that do not support the HIGH or MEDIUM safety levels
#pod (for example Win NT or OS/2) any attempt to change the level will
#pod be ignored. The decision to ignore rather than raise an exception
#pod allows portable programs to be written with high security in mind
#pod for the systems that can support this without those programs failing
#pod on systems where the extra tests are irrelevant.
#pod
#pod If you really need to see whether the change has been accepted
#pod simply examine the return value of C<safe_level>.
#pod
#pod   $newlevel = File::Temp->safe_level( File::Temp::HIGH );
#pod   die "Could not change to high security"
#pod       if $newlevel != File::Temp::HIGH;
#pod
#pod Available since 0.05.
#pod
#pod =cut

{
  # protect from using the variable itself
  my $LEVEL = STANDARD;
  sub safe_level {
    my $self = shift;
    if (@_) {
      my $level = shift;
      if (($level != STANDARD) && ($level != MEDIUM) && ($level != HIGH)) {
        carp "safe_level: Specified level ($level) not STANDARD, MEDIUM or HIGH - ignoring\n" if $^W;
      } else {
        # Don't allow this on perl 5.005 or earlier
        if ($] < 5.006 && $level != STANDARD) {
          # Cant do MEDIUM or HIGH checks
          croak "Currently requires perl 5.006 or newer to do the safe checks";
        }
        # Check that we are allowed to change level
        # Silently ignore if we can not.
        $LEVEL = $level if _can_do_level($level);
      }
    }
    return $LEVEL;
  }
}

#pod =item TopSystemUID
#pod
#pod This is the highest UID on the current system that refers to a root
#pod UID. This is used to make sure that the temporary directory is
#pod owned by a system UID (C<root>, C<bin>, C<sys> etc) rather than
#pod simply by root.
#pod
#pod This is required since on many unix systems C</tmp> is not owned
#pod by root.
#pod
#pod Default is to assume that any UID less than or equal to 10 is a root
#pod UID.
#pod
#pod   File::Temp->top_system_uid(10);
#pod   my $topid = File::Temp->top_system_uid;
#pod
#pod This value can be adjusted to reduce security checking if required.
#pod The value is only relevant when C<safe_level> is set to MEDIUM or higher.
#pod
#pod Available since 0.05.
#pod
#pod =cut

{
  my $TopSystemUID = 10;
  $TopSystemUID = 197108 if $^O eq 'interix'; # "Administrator"
  sub top_system_uid {
    my $self = shift;
    if (@_) {
      my $newuid = shift;
      croak "top_system_uid: UIDs should be numeric"
        unless $newuid =~ /^\d+$/s;
      $TopSystemUID = $newuid;
    }
    return $TopSystemUID;
  }
}

#pod =item B<$KEEP_ALL>
#pod
#pod Controls whether temporary files and directories should be retained
#pod regardless of any instructions in the program to remove them
#pod automatically.  This is useful for debugging but should not be used in
#pod production code.
#pod
#pod   $File::Temp::KEEP_ALL = 1;
#pod
#pod Default is for files to be removed as requested by the caller.
#pod
#pod In some cases, files will only be retained if this variable is true
#pod when the file is created. This means that you can not create a temporary
#pod file, set this variable and expect the temp file to still be around
#pod when the program exits.
#pod
#pod =item B<$DEBUG>
#pod
#pod Controls whether debugging messages should be enabled.
#pod
#pod   $File::Temp::DEBUG = 1;
#pod
#pod Default is for debugging mode to be disabled.
#pod
#pod Available since 0.15.
#pod
#pod =back
#pod
#pod =head1 WARNING
#pod
#pod For maximum security, endeavour always to avoid ever looking at,
#pod touching, or even imputing the existence of the filename.  You do not
#pod know that that filename is connected to the same file as the handle
#pod you have, and attempts to check this can only trigger more race
#pod conditions.  It's far more secure to use the filehandle alone and
#pod dispense with the filename altogether.
#pod
#pod If you need to pass the handle to something that expects a filename
#pod then on a unix system you can use C<"/dev/fd/" . fileno($fh)> for
#pod arbitrary programs. Perl code that uses the 2-argument version of
#pod C<< open >> can be passed C<< "+<=&" . fileno($fh) >>. Otherwise you
#pod will need to pass the filename. You will have to clear the
#pod close-on-exec bit on that file descriptor before passing it to another
#pod process.
#pod
#pod     use Fcntl qw/F_SETFD F_GETFD/;
#pod     fcntl($tmpfh, F_SETFD, 0)
#pod         or die "Can't clear close-on-exec flag on temp fh: $!\n";
#pod
#pod =head2 Temporary files and NFS
#pod
#pod Some problems are associated with using temporary files that reside
#pod on NFS file systems and it is recommended that a local filesystem
#pod is used whenever possible. Some of the security tests will most probably
#pod fail when the temp file is not local. Additionally, be aware that
#pod the performance of I/O operations over NFS will not be as good as for
#pod a local disk.
#pod
#pod =head2 Forking
#pod
#pod In some cases files created by File::Temp are removed from within an
#pod END block. Since END blocks are triggered when a child process exits
#pod (unless C<POSIX::_exit()> is used by the child) File::Temp takes care
#pod to only remove those temp files created by a particular process ID. This
#pod means that a child will not attempt to remove temp files created by the
#pod parent process.
#pod
#pod If you are forking many processes in parallel that are all creating
#pod temporary files, you may need to reset the random number seed using
#pod srand(EXPR) in each child else all the children will attempt to walk
#pod through the same set of random file names and may well cause
#pod themselves to give up if they exceed the number of retry attempts.
#pod
#pod =head2 Directory removal
#pod
#pod Note that if you have chdir'ed into the temporary directory and it is
#pod subsequently cleaned up (either in the END block or as part of object
#pod destruction), then you will get a warning from File::Path::rmtree().
#pod
#pod =head2 Taint mode
#pod
#pod If you need to run code under taint mode, updating to the latest
#pod L<File::Spec> is highly recommended.  On Windows, if the directory
#pod given by L<File::Spec::tmpdir> isn't writable, File::Temp will attempt
#pod to fallback to the user's local application data directory or croak
#pod with an error.
#pod
#pod =head2 BINMODE
#pod
#pod The file returned by File::Temp will have been opened in binary mode
#pod if such a mode is available. If that is not correct, use the C<binmode()>
#pod function to change the mode of the filehandle.
#pod
#pod Note that you can modify the encoding of a file opened by File::Temp
#pod also by using C<binmode()>.
#pod
#pod =head1 HISTORY
#pod
#pod Originally began life in May 1999 as an XS interface to the system
#pod mkstemp() function. In March 2000, the OpenBSD mkstemp() code was
#pod translated to Perl for total control of the code's
#pod security checking, to ensure the presence of the function regardless of
#pod operating system and to help with portability. The module was shipped
#pod as a standard part of perl from v5.6.1.
#pod
#pod Thanks to Tom Christiansen for suggesting that this module
#pod should be written and providing ideas for code improvements and
#pod security enhancements.
#pod
#pod =head1 SEE ALSO
#pod
#pod L<POSIX/tmpnam>, L<POSIX/tmpfile>, L<File::Spec>, L<File::Path>
#pod
#pod See L<IO::File> and L<File::MkTemp>, L<Apache::TempFile> for
#pod different implementations of temporary file handling.
#pod
#pod See L<File::Tempdir> for an alternative object-oriented wrapper for
#pod the C<tempdir> function.
#pod
#pod =cut

package ## hide from PAUSE
  File::Temp::Dir;

our $VERSION = '0.2311';

use File::Path qw/ rmtree /;
use strict;
use overload '""' => "STRINGIFY",
  '0+' => \&File::Temp::NUMIFY,
  fallback => 1;

# private class specifically to support tempdir objects
# created by File::Temp->newdir

# ostensibly the same method interface as File::Temp but without
# inheriting all the IO::Seekable methods and other cruft

# Read-only - returns the name of the temp directory

sub dirname {
  my $self = shift;
  return $self->{DIRNAME};
}

sub STRINGIFY {
  my $self = shift;
  return $self->dirname;
}

sub unlink_on_destroy {
  my $self = shift;
  if (@_) {
    $self->{CLEANUP} = shift;
  }
  return $self->{CLEANUP};
}

sub DESTROY {
  my $self = shift;
  local($., $@, $!, $^E, $?);
  if ($self->unlink_on_destroy && 
      $$ == $self->{LAUNCHPID} && !$File::Temp::KEEP_ALL) {
    if (-d $self->{REALNAME}) {
      # Some versions of rmtree will abort if you attempt to remove
      # the directory you are sitting in. We protect that and turn it
      # into a warning. We do this because this occurs during object
      # destruction and so can not be caught by the user.
      eval { rmtree($self->{REALNAME}, $File::Temp::DEBUG, 0); };
      warn $@ if ($@ && $^W);
    }
  }
}

1;


# vim: ts=2 sts=2 sw=2 et:

__END__

=pod

=encoding UTF-8

=head1 NAME

File::Temp - return name and handle of a temporary file safely

=head1 VERSION

version 0.2311

=head1 SYNOPSIS

  use File::Temp qw/ tempfile tempdir /;

  $fh = tempfile();
  ($fh, $filename) = tempfile();

  ($fh, $filename) = tempfile( $template, DIR => $dir);
  ($fh, $filename) = tempfile( $template, SUFFIX => '.dat');
  ($fh, $filename) = tempfile( $template, TMPDIR => 1 );

  binmode( $fh, ":utf8" );

  $dir = tempdir( CLEANUP => 1 );
  ($fh, $filename) = tempfile( DIR => $dir );

Object interface:

  require File::Temp;
  use File::Temp ();
  use File::Temp qw/ :seekable /;

  $fh = File::Temp->new();
  $fname = $fh->filename;

  $fh = File::Temp->new(TEMPLATE => $template);
  $fname = $fh->filename;

  $tmp = File::Temp->new( UNLINK => 0, SUFFIX => '.dat' );
  print $tmp "Some data\n";
  print "Filename is $tmp\n";
  $tmp->seek( 0, SEEK_END );

  $dir = File::Temp->newdir(); # CLEANUP => 1 by default

The following interfaces are provided for compatibility with
existing APIs. They should not be used in new code.

MkTemp family:

  use File::Temp qw/ :mktemp  /;

  ($fh, $file) = mkstemp( "tmpfileXXXXX" );
  ($fh, $file) = mkstemps( "tmpfileXXXXXX", $suffix);

  $tmpdir = mkdtemp( $template );

  $unopened_file = mktemp( $template );

POSIX functions:

  use File::Temp qw/ :POSIX /;

  $file = tmpnam();
  $fh = tmpfile();

  ($fh, $file) = tmpnam();

Compatibility functions:

  $unopened_file = File::Temp::tempnam( $dir, $pfx );

=head1 DESCRIPTION

C<File::Temp> can be used to create and open temporary files in a safe
way.  There is both a function interface and an object-oriented
interface.  The File::Temp constructor or the tempfile() function can
be used to return the name and the open filehandle of a temporary
file.  The tempdir() function can be used to create a temporary
directory.

The security aspect of temporary file creation is emphasized such that
a filehandle and filename are returned together.  This helps guarantee
that a race condition can not occur where the temporary file is
created by another process between checking for the existence of the
file and its opening.  Additional security levels are provided to
check, for example, that the sticky bit is set on world writable
directories.  See L<"safe_level"> for more information.

For compatibility with popular C library functions, Perl implementations of
the mkstemp() family of functions are provided. These are, mkstemp(),
mkstemps(), mkdtemp() and mktemp().

Additionally, implementations of the standard L<POSIX|POSIX>
tmpnam() and tmpfile() functions are provided if required.

Implementations of mktemp(), tmpnam(), and tempnam() are provided,
but should be used with caution since they return only a filename
that was valid when function was called, so cannot guarantee
that the file will not exist by the time the caller opens the filename.

Filehandles returned by these functions support the seekable methods.

=begin :__INTERNALS

=head1 PORTABILITY

This section is at the top in order to provide easier access to
porters.  It is not expected to be rendered by a standard pod
formatting tool. Please skip straight to the SYNOPSIS section if you
are not trying to port this module to a new platform.

This module is designed to be portable across operating systems and it
currently supports Unix, VMS, DOS, OS/2, Windows and Mac OS
(Classic). When porting to a new OS there are generally three main
issues that have to be solved:

=over 4

=item *

Can the OS unlink an open file? If it can not then the
C<_can_unlink_opened_file> method should be modified.

=item *

Are the return values from C<stat> reliable? By default all the
return values from C<stat> are compared when unlinking a temporary
file using the filename and the handle. Operating systems other than
unix do not always have valid entries in all fields. If utility function
C<File::Temp::unlink0> fails then the C<stat> comparison should be
modified accordingly.

=item *

Security. Systems that can not support a test for the sticky bit
on a directory can not use the MEDIUM and HIGH security tests.
The C<_can_do_level> method should be modified accordingly.

=back

=end :__INTERNALS

=head1 OBJECT-ORIENTED INTERFACE

This is the primary interface for interacting with
C<File::Temp>. Using the OO interface a temporary file can be created
when the object is constructed and the file can be removed when the
object is no longer required.

Note that there is no method to obtain the filehandle from the
C<File::Temp> object. The object itself acts as a filehandle.  The object
isa C<IO::Handle> and isa C<IO::Seekable> so all those methods are
available.

Also, the object is configured such that it stringifies to the name of the
temporary file and so can be compared to a filename directly.  It numifies
to the C<refaddr> the same as other handles and so can be compared to other
handles with C<==>.

    $fh eq $filename       # as a string
    $fh != \*STDOUT        # as a number

Available since 0.14.

=over 4

=item B<new>

Create a temporary file object.

  my $tmp = File::Temp->new();

by default the object is constructed as if C<tempfile>
was called without options, but with the additional behaviour
that the temporary file is removed by the object destructor
if UNLINK is set to true (the default).

Supported arguments are the same as for C<tempfile>: UNLINK
(defaulting to true), DIR, EXLOCK, PERMS and SUFFIX.
Additionally, the filename
template is specified using the TEMPLATE option. The OPEN option
is not supported (the file is always opened).

 $tmp = File::Temp->new( TEMPLATE => 'tempXXXXX',
                        DIR => 'mydir',
                        SUFFIX => '.dat');

Arguments are case insensitive.

Can call croak() if an error occurs.

Available since 0.14.

TEMPLATE available since 0.23

=item B<newdir>

Create a temporary directory using an object oriented interface.

  $dir = File::Temp->newdir();

By default the directory is deleted when the object goes out of scope.

Supports the same options as the C<tempdir> function. Note that directories
created with this method default to CLEANUP => 1.

  $dir = File::Temp->newdir( $template, %options );

A template may be specified either with a leading template or
with a TEMPLATE argument.

Available since 0.19.

TEMPLATE available since 0.23.

=item B<filename>

Return the name of the temporary file associated with this object
(if the object was created using the "new" constructor).

  $filename = $tmp->filename;

This method is called automatically when the object is used as
a string.

Current API available since 0.14

=item B<dirname>

Return the name of the temporary directory associated with this
object (if the object was created using the "newdir" constructor).

  $dirname = $tmpdir->dirname;

This method is called automatically when the object is used in string context.

=item B<unlink_on_destroy>

Control whether the file is unlinked when the object goes out of scope.
The file is removed if this value is true and $KEEP_ALL is not.

 $fh->unlink_on_destroy( 1 );

Default is for the file to be removed.

Current API available since 0.15

=item B<DESTROY>

When the object goes out of scope, the destructor is called. This
destructor will attempt to unlink the file (using L<unlink1|"unlink1">)
if the constructor was called with UNLINK set to 1 (the default state
if UNLINK is not specified).

No error is given if the unlink fails.

If the object has been passed to a child process during a fork, the
file will be deleted when the object goes out of scope in the parent.

For a temporary directory object the directory will be removed unless
the CLEANUP argument was used in the constructor (and set to false) or
C<unlink_on_destroy> was modified after creation.  Note that if a temp
directory is your current directory, it cannot be removed - a warning
will be given in this case.  C<chdir()> out of the directory before
letting the object go out of scope.

If the global variable $KEEP_ALL is true, the file or directory
will not be removed.

=back

=head1 FUNCTIONS

This section describes the recommended interface for generating
temporary files and directories.

=over 4

=item B<tempfile>

This is the basic function to generate temporary files.
The behaviour of the file can be changed using various options:

  $fh = tempfile();
  ($fh, $filename) = tempfile();

Create a temporary file in  the directory specified for temporary
files, as specified by the tmpdir() function in L<File::Spec>.

  ($fh, $filename) = tempfile($template);

Create a temporary file in the current directory using the supplied
template.  Trailing `X' characters are replaced with random letters to
generate the filename.  At least four `X' characters must be present
at the end of the template.

  ($fh, $filename) = tempfile($template, SUFFIX => $suffix)

Same as previously, except that a suffix is added to the template
after the `X' translation.  Useful for ensuring that a temporary
filename has a particular extension when needed by other applications.
But see the WARNING at the end.

  ($fh, $filename) = tempfile($template, DIR => $dir);

Translates the template as before except that a directory name
is specified.

  ($fh, $filename) = tempfile($template, TMPDIR => 1);

Equivalent to specifying a DIR of "File::Spec->tmpdir", writing the file
into the same temporary directory as would be used if no template was
specified at all.

  ($fh, $filename) = tempfile($template, UNLINK => 1);

Return the filename and filehandle as before except that the file is
automatically removed when the program exits (dependent on
$KEEP_ALL). Default is for the file to be removed if a file handle is
requested and to be kept if the filename is requested. In a scalar
context (where no filename is returned) the file is always deleted
either (depending on the operating system) on exit or when it is
closed (unless $KEEP_ALL is true when the temp file is created).

Use the object-oriented interface if fine-grained control of when
a file is removed is required.

If the template is not specified, a template is always
automatically generated. This temporary file is placed in tmpdir()
(L<File::Spec>) unless a directory is specified explicitly with the
DIR option.

  $fh = tempfile( DIR => $dir );

If called in scalar context, only the filehandle is returned and the
file will automatically be deleted when closed on operating systems
that support this (see the description of tmpfile() elsewhere in this
document).  This is the preferred mode of operation, as if you only
have a filehandle, you can never create a race condition by fumbling
with the filename. On systems that can not unlink an open file or can
not mark a file as temporary when it is opened (for example, Windows
NT uses the C<O_TEMPORARY> flag) the file is marked for deletion when
the program ends (equivalent to setting UNLINK to 1). The C<UNLINK>
flag is ignored if present.

  (undef, $filename) = tempfile($template, OPEN => 0);

This will return the filename based on the template but
will not open this file.  Cannot be used in conjunction with
UNLINK set to true. Default is to always open the file
to protect from possible race conditions. A warning is issued
if warnings are turned on. Consider using the tmpnam()
and mktemp() functions described elsewhere in this document
if opening the file is not required.

To open the temporary filehandle with O_EXLOCK (open with exclusive
file lock) use C<< EXLOCK=>1 >>. This is supported only by some
operating systems (most notably BSD derived systems). By default
EXLOCK will be false. Former C<File::Temp> versions set EXLOCK to
true, so to be sure to get an unlocked filehandle also with older
versions, explicitly set C<< EXLOCK=>0 >>.

  ($fh, $filename) = tempfile($template, EXLOCK => 1);

By default, the temp file is created with 0600 file permissions.
Use C<PERMS> to change this:

  ($fh, $filename) = tempfile($template, PERMS => 0666);

Options can be combined as required.

Will croak() if there is an error.

Available since 0.05.

UNLINK flag available since 0.10.

TMPDIR flag available since 0.19.

EXLOCK flag available since 0.19.

PERMS flag available since 0.2310.

=item B<tempdir>

This is the recommended interface for creation of temporary
directories.  By default the directory will not be removed on exit
(that is, it won't be temporary; this behaviour can not be changed
because of issues with backwards compatibility). To enable removal
either use the CLEANUP option which will trigger removal on program
exit, or consider using the "newdir" method in the object interface which
will allow the directory to be cleaned up when the object goes out of
scope.

The behaviour of the function depends on the arguments:

  $tempdir = tempdir();

Create a directory in tmpdir() (see L<File::Spec|File::Spec>).

  $tempdir = tempdir( $template );

Create a directory from the supplied template. This template is
similar to that described for tempfile(). `X' characters at the end
of the template are replaced with random letters to construct the
directory name. At least four `X' characters must be in the template.

  $tempdir = tempdir ( DIR => $dir );

Specifies the directory to use for the temporary directory.
The temporary directory name is derived from an internal template.

  $tempdir = tempdir ( $template, DIR => $dir );

Prepend the supplied directory name to the template. The template
should not include parent directory specifications itself. Any parent
directory specifications are removed from the template before
prepending the supplied directory.

  $tempdir = tempdir ( $template, TMPDIR => 1 );

Using the supplied template, create the temporary directory in
a standard location for temporary files. Equivalent to doing

  $tempdir = tempdir ( $template, DIR => File::Spec->tmpdir);

but shorter. Parent directory specifications are stripped from the
template itself. The C<TMPDIR> option is ignored if C<DIR> is set
explicitly.  Additionally, C<TMPDIR> is implied if neither a template
nor a directory are supplied.

  $tempdir = tempdir( $template, CLEANUP => 1);

Create a temporary directory using the supplied template, but
attempt to remove it (and all files inside it) when the program
exits. Note that an attempt will be made to remove all files from
the directory even if they were not created by this module (otherwise
why ask to clean it up?). The directory removal is made with
the rmtree() function from the L<File::Path|File::Path> module.
Of course, if the template is not specified, the temporary directory
will be created in tmpdir() and will also be removed at program exit.

Will croak() if there is an error.

Current API available since 0.05.

=back

=head1 MKTEMP FUNCTIONS

The following functions are Perl implementations of the
mktemp() family of temp file generation system calls.

=over 4

=item B<mkstemp>

Given a template, returns a filehandle to the temporary file and the name
of the file.

  ($fh, $name) = mkstemp( $template );

In scalar context, just the filehandle is returned.

The template may be any filename with some number of X's appended
to it, for example F</tmp/temp.XXXX>. The trailing X's are replaced
with unique alphanumeric combinations.

Will croak() if there is an error.

Current API available since 0.05.

=item B<mkstemps>

Similar to mkstemp(), except that an extra argument can be supplied
with a suffix to be appended to the template.

  ($fh, $name) = mkstemps( $template, $suffix );

For example a template of C<testXXXXXX> and suffix of C<.dat>
would generate a file similar to F<testhGji_w.dat>.

Returns just the filehandle alone when called in scalar context.

Will croak() if there is an error.

Current API available since 0.05.

=item B<mkdtemp>

Create a directory from a template. The template must end in
X's that are replaced by the routine.

  $tmpdir_name = mkdtemp($template);

Returns the name of the temporary directory created.

Directory must be removed by the caller.

Will croak() if there is an error.

Current API available since 0.05.

=item B<mktemp>

Returns a valid temporary filename but does not guarantee
that the file will not be opened by someone else.

  $unopened_file = mktemp($template);

Template is the same as that required by mkstemp().

Will croak() if there is an error.

Current API available since 0.05.

=back

=head1 POSIX FUNCTIONS

This section describes the re-implementation of the tmpnam()
and tmpfile() functions described in L<POSIX>
using the mkstemp() from this module.

Unlike the L<POSIX|POSIX> implementations, the directory used
for the temporary file is not specified in a system include
file (C<P_tmpdir>) but simply depends on the choice of tmpdir()
returned by L<File::Spec|File::Spec>. On some implementations this
location can be set using the C<TMPDIR> environment variable, which
may not be secure.
If this is a problem, simply use mkstemp() and specify a template.

=over 4

=item B<tmpnam>

When called in scalar context, returns the full name (including path)
of a temporary file (uses mktemp()). The only check is that the file does
not already exist, but there is no guarantee that that condition will
continue to apply.

  $file = tmpnam();

When called in list context, a filehandle to the open file and
a filename are returned. This is achieved by calling mkstemp()
after constructing a suitable template.

  ($fh, $file) = tmpnam();

If possible, this form should be used to prevent possible
race conditions.

See L<File::Spec/tmpdir> for information on the choice of temporary
directory for a particular operating system.

Will croak() if there is an error.

Current API available since 0.05.

=item B<tmpfile>

Returns the filehandle of a temporary file.

  $fh = tmpfile();

The file is removed when the filehandle is closed or when the program
exits. No access to the filename is provided.

If the temporary file can not be created undef is returned.
Currently this command will probably not work when the temporary
directory is on an NFS file system.

Will croak() if there is an error.

Available since 0.05.

Returning undef if unable to create file added in 0.12.

=back

=head1 ADDITIONAL FUNCTIONS

These functions are provided for backwards compatibility
with common tempfile generation C library functions.

They are not exported and must be addressed using the full package
name.

=over 4

=item B<tempnam>

Return the name of a temporary file in the specified directory
using a prefix. The file is guaranteed not to exist at the time
the function was called, but such guarantees are good for one
clock tick only.  Always use the proper form of C<sysopen>
with C<O_CREAT | O_EXCL> if you must open such a filename.

  $filename = File::Temp::tempnam( $dir, $prefix );

Equivalent to running mktemp() with $dir/$prefixXXXXXXXX
(using unix file convention as an example)

Because this function uses mktemp(), it can suffer from race conditions.

Will croak() if there is an error.

Current API available since 0.05.

=back

=head1 UTILITY FUNCTIONS

Useful functions for dealing with the filehandle and filename.

=over 4

=item B<unlink0>

Given an open filehandle and the associated filename, make a safe
unlink. This is achieved by first checking that the filename and
filehandle initially point to the same file and that the number of
links to the file is 1 (all fields returned by stat() are compared).
Then the filename is unlinked and the filehandle checked once again to
verify that the number of links on that file is now 0.  This is the
closest you can come to making sure that the filename unlinked was the
same as the file whose descriptor you hold.

  unlink0($fh, $path)
     or die "Error unlinking file $path safely";

Returns false on error but croaks() if there is a security
anomaly. The filehandle is not closed since on some occasions this is
not required.

On some platforms, for example Windows NT, it is not possible to
unlink an open file (the file must be closed first). On those
platforms, the actual unlinking is deferred until the program ends and
good status is returned. A check is still performed to make sure that
the filehandle and filename are pointing to the same thing (but not at
the time the end block is executed since the deferred removal may not
have access to the filehandle).

Additionally, on Windows NT not all the fields returned by stat() can
be compared. For example, the C<dev> and C<rdev> fields seem to be
different.  Also, it seems that the size of the file returned by stat()
does not always agree, with C<stat(FH)> being more accurate than
C<stat(filename)>, presumably because of caching issues even when
using autoflush (this is usually overcome by waiting a while after
writing to the tempfile before attempting to C<unlink0> it).

Finally, on NFS file systems the link count of the file handle does
not always go to zero immediately after unlinking. Currently, this
command is expected to fail on NFS disks.

This function is disabled if the global variable $KEEP_ALL is true
and an unlink on open file is supported. If the unlink is to be deferred
to the END block, the file is still registered for removal.

This function should not be called if you are using the object oriented
interface since the it will interfere with the object destructor deleting
the file.

Available Since 0.05.

If can not unlink open file, defer removal until later available since 0.06.

=item B<cmpstat>

Compare C<stat> of filehandle with C<stat> of provided filename.  This
can be used to check that the filename and filehandle initially point
to the same file and that the number of links to the file is 1 (all
fields returned by stat() are compared).

  cmpstat($fh, $path)
     or die "Error comparing handle with file";

Returns false if the stat information differs or if the link count is
greater than 1. Calls croak if there is a security anomaly.

On certain platforms, for example Windows, not all the fields returned by stat()
can be compared. For example, the C<dev> and C<rdev> fields seem to be
different in Windows.  Also, it seems that the size of the file
returned by stat() does not always agree, with C<stat(FH)> being more
accurate than C<stat(filename)>, presumably because of caching issues
even when using autoflush (this is usually overcome by waiting a while
after writing to the tempfile before attempting to C<unlink0> it).

Not exported by default.

Current API available since 0.14.

=item B<unlink1>

Similar to C<unlink0> except after file comparison using cmpstat, the
filehandle is closed prior to attempting to unlink the file. This
allows the file to be removed without using an END block, but does
mean that the post-unlink comparison of the filehandle state provided
by C<unlink0> is not available.

  unlink1($fh, $path)
     or die "Error closing and unlinking file";

Usually called from the object destructor when using the OO interface.

Not exported by default.

This function is disabled if the global variable $KEEP_ALL is true.

Can call croak() if there is a security anomaly during the stat()
comparison.

Current API available since 0.14.

=item B<cleanup>

Calling this function will cause any temp files or temp directories
that are registered for removal to be removed. This happens automatically
when the process exits but can be triggered manually if the caller is sure
that none of the temp files are required. This method can be registered as
an Apache callback.

Note that if a temp directory is your current directory, it cannot be
removed.  C<chdir()> out of the directory first before calling
C<cleanup()>. (For the cleanup at program exit when the CLEANUP flag
is set, this happens automatically.)

On OSes where temp files are automatically removed when the temp file
is closed, calling this function will have no effect other than to remove
temporary directories (which may include temporary files).

  File::Temp::cleanup();

Not exported by default.

Current API available since 0.15.

=back

=head1 PACKAGE VARIABLES

These functions control the global state of the package.

=over 4

=item B<safe_level>

Controls the lengths to which the module will go to check the safety of the
temporary file or directory before proceeding.
Options are:

=over 8

=item STANDARD

Do the basic security measures to ensure the directory exists and is
writable, that temporary files are opened only if they do not already
exist, and that possible race conditions are avoided.  Finally the
L<unlink0|"unlink0"> function is used to remove files safely.

=item MEDIUM

In addition to the STANDARD security, the output directory is checked
to make sure that it is owned either by root or the user running the
program. If the directory is writable by group or by other, it is then
checked to make sure that the sticky bit is set.

Will not work on platforms that do not support the C<-k> test
for sticky bit.

=item HIGH

In addition to the MEDIUM security checks, also check for the
possibility of ``chown() giveaway'' using the L<POSIX|POSIX>
sysconf() function. If this is a possibility, each directory in the
path is checked in turn for safeness, recursively walking back to the
root directory.

For platforms that do not support the L<POSIX|POSIX>
C<_PC_CHOWN_RESTRICTED> symbol (for example, Windows NT) it is
assumed that ``chown() giveaway'' is possible and the recursive test
is performed.

=back

The level can be changed as follows:

  File::Temp->safe_level( File::Temp::HIGH );

The level constants are not exported by the module.

Currently, you must be running at least perl v5.6.0 in order to
run with MEDIUM or HIGH security. This is simply because the
safety tests use functions from L<Fcntl|Fcntl> that are not
available in older versions of perl. The problem is that the version
number for Fcntl is the same in perl 5.6.0 and in 5.005_03 even though
they are different versions.

On systems that do not support the HIGH or MEDIUM safety levels
(for example Win NT or OS/2) any attempt to change the level will
be ignored. The decision to ignore rather than raise an exception
allows portable programs to be written with high security in mind
for the systems that can support this without those programs failing
on systems where the extra tests are irrelevant.

If you really need to see whether the change has been accepted
simply examine the return value of C<safe_level>.

  $newlevel = File::Temp->safe_level( File::Temp::HIGH );
  die "Could not change to high security"
      if $newlevel != File::Temp::HIGH;

Available since 0.05.

=item TopSystemUID

This is the highest UID on the current system that refers to a root
UID. This is used to make sure that the temporary directory is
owned by a system UID (C<root>, C<bin>, C<sys> etc) rather than
simply by root.

This is required since on many unix systems C</tmp> is not owned
by root.

Default is to assume that any UID less than or equal to 10 is a root
UID.

  File::Temp->top_system_uid(10);
  my $topid = File::Temp->top_system_uid;

This value can be adjusted to reduce security checking if required.
The value is only relevant when C<safe_level> is set to MEDIUM or higher.

Available since 0.05.

=item B<$KEEP_ALL>

Controls whether temporary files and directories should be retained
regardless of any instructions in the program to remove them
automatically.  This is useful for debugging but should not be used in
production code.

  $File::Temp::KEEP_ALL = 1;

Default is for files to be removed as requested by the caller.

In some cases, files will only be retained if this variable is true
when the file is created. This means that you can not create a temporary
file, set this variable and expect the temp file to still be around
when the program exits.

=item B<$DEBUG>

Controls whether debugging messages should be enabled.

  $File::Temp::DEBUG = 1;

Default is for debugging mode to be disabled.

Available since 0.15.

=back

=head1 WARNING

For maximum security, endeavour always to avoid ever looking at,
touching, or even imputing the existence of the filename.  You do not
know that that filename is connected to the same file as the handle
you have, and attempts to check this can only trigger more race
conditions.  It's far more secure to use the filehandle alone and
dispense with the filename altogether.

If you need to pass the handle to something that expects a filename
then on a unix system you can use C<"/dev/fd/" . fileno($fh)> for
arbitrary programs. Perl code that uses the 2-argument version of
C<< open >> can be passed C<< "+<=&" . fileno($fh) >>. Otherwise you
will need to pass the filename. You will have to clear the
close-on-exec bit on that file descriptor before passing it to another
process.

    use Fcntl qw/F_SETFD F_GETFD/;
    fcntl($tmpfh, F_SETFD, 0)
        or die "Can't clear close-on-exec flag on temp fh: $!\n";

=head2 Temporary files and NFS

Some problems are associated with using temporary files that reside
on NFS file systems and it is recommended that a local filesystem
is used whenever possible. Some of the security tests will most probably
fail when the temp file is not local. Additionally, be aware that
the performance of I/O operations over NFS will not be as good as for
a local disk.

=head2 Forking

In some cases files created by File::Temp are removed from within an
END block. Since END blocks are triggered when a child process exits
(unless C<POSIX::_exit()> is used by the child) File::Temp takes care
to only remove those temp files created by a particular process ID. This
means that a child will not attempt to remove temp files created by the
parent process.

If you are forking many processes in parallel that are all creating
temporary files, you may need to reset the random number seed using
srand(EXPR) in each child else all the children will attempt to walk
through the same set of random file names and may well cause
themselves to give up if they exceed the number of retry attempts.

=head2 Directory removal

Note that if you have chdir'ed into the temporary directory and it is
subsequently cleaned up (either in the END block or as part of object
destruction), then you will get a warning from File::Path::rmtree().

=head2 Taint mode

If you need to run code under taint mode, updating to the latest
L<File::Spec> is highly recommended.  On Windows, if the directory
given by L<File::Spec::tmpdir> isn't writable, File::Temp will attempt
to fallback to the user's local application data directory or croak
with an error.

=head2 BINMODE

The file returned by File::Temp will have been opened in binary mode
if such a mode is available. If that is not correct, use the C<binmode()>
function to change the mode of the filehandle.

Note that you can modify the encoding of a file opened by File::Temp
also by using C<binmode()>.

=head1 HISTORY

Originally began life in May 1999 as an XS interface to the system
mkstemp() function. In March 2000, the OpenBSD mkstemp() code was
translated to Perl for total control of the code's
security checking, to ensure the presence of the function regardless of
operating system and to help with portability. The module was shipped
as a standard part of perl from v5.6.1.

Thanks to Tom Christiansen for suggesting that this module
should be written and providing ideas for code improvements and
security enhancements.

=head1 SEE ALSO

L<POSIX/tmpnam>, L<POSIX/tmpfile>, L<File::Spec>, L<File::Path>

See L<IO::File> and L<File::MkTemp>, L<Apache::TempFile> for
different implementations of temporary file handling.

See L<File::Tempdir> for an alternative object-oriented wrapper for
the C<tempdir> function.

=for Pod::Coverage STRINGIFY NUMIFY top_system_uid

=head1 SUPPORT

Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=File-Temp>
(or L<bug-File-Temp@rt.cpan.org|mailto:bug-File-Temp@rt.cpan.org>).

There is also a mailing list available for users of this distribution, at
L<http://lists.perl.org/list/cpan-workers.html>.

There is also an irc channel available for users of this distribution, at
L<C<#toolchain> on C<irc.perl.org>|irc://irc.perl.org/#toolchain>.

=head1 AUTHOR

Tim Jenness <tjenness@cpan.org>

=head1 CONTRIBUTORS

=for stopwords Tim Jenness Karen Etheridge David Golden Slaven Rezic mohawk2 Roy Ivy III Peter Rabbitson Olivier Mengué John Acklam Gim Yee Nicolas R Brian Mowrey Dagfinn Ilmari Mannsåker Steinbrunner Ed Avis Guillem Jover James E. Keenan Kevin Ryde Ben Tilly

=over 4

=item *

Tim Jenness <t.jenness@jach.hawaii.edu>

=item *

Karen Etheridge <ether@cpan.org>

=item *

David Golden <dagolden@cpan.org>

=item *

Slaven Rezic <srezic@cpan.org>

=item *

mohawk2 <mohawk2@users.noreply.github.com>

=item *

Roy Ivy III <rivy.dev@gmail.com>

=item *

Peter Rabbitson <ribasushi@cpan.org>

=item *

Olivier Mengué <dolmen@cpan.org>

=item *

Peter John Acklam <pjacklam@online.no>

=item *

Tim Gim Yee <tim.gim.yee@gmail.com>

=item *

Nicolas R <atoomic@cpan.org>

=item *

Brian Mowrey <brian@drlabs.org>

=item *

Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>

=item *

David Steinbrunner <dsteinbrunner@pobox.com>

=item *

Ed Avis <eda@linux01.wcl.local>

=item *

Guillem Jover <guillem@hadrons.org>

=item *

James E. Keenan <jkeen@verizon.net>

=item *

Kevin Ryde <user42@zip.com.au>

=item *

Ben Tilly <btilly@gmail.com>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2020 by Tim Jenness and the UK Particle Physics and Astronomy Research Council.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    های پیشفرض صفحه کلید (${XKBOPTIONS}) حفظ شود؟
Description-fi.utf-8: Säilytetäänkö näppäimistön oletusasetukset (${XKBOPTIONS})?
Description-fr.utf-8: Conserver les options par défaut du clavier (${XKBOPTIONS}) ?
Description-ga.utf-8: An bhfuil fonn ort na roghanna réamhshocraithe méarchláir a choinneáil (${XKBOPTIONS})?
Description-gl.utf-8: Desexa manter as opcións de teclado predeterminadas (${XKBOPTIONS})?
Description-gu.utf-8: મૂળભૂત કીબોર્ડ વિકલ્પો (${XKBOPTIONS}) રાખશો?
Description-he.utf-8: לשמור על אפשרויות בררת המחדל של המקלדת (${XKBOPTIONS})?
Description-hi.utf-8: डिफाल्ट कुंजीपटल विकल्प (${XKBOPTIONS}) रखें?
Description-hr.utf-8: Zadrži zadane mogućnosti tipkovnice (${XKBOPTIONS})?
Description-hu.utf-8: Megtartod az alap billentyűzet opciókat (${XKBOPTIONS})?
Description-id.utf-8: Gunakan pilihan pola keyboard saat ini: (${XKBOPTIONS})?
Description-is.utf-8: Halda sjálfgefnum lyklaborðsstillingum (${XKBOPTIONS})?
Description-it.utf-8: Mantenere la disposizione predefinita della tastiera (${XKBOPTIONS})?
Description-ja.utf-8: デフォルトのキーボードオプション (${XKBOPTIONS}) を保持しますか?
Description-kab.utf-8: Eǧǧ tixtiṛiyin n unasiw timezwer (${XKBOPTIONS})?
Description-kk.utf-8: Бастапқы пернетақта опцияларын (${XKBOPTIONS}) қалдыру керек пе?
Description-km.utf-8: រក្សាទុក​ជម្រើស​ក្ដារចុច​លំនាំដើម (${XKBOPTIONS})?
Description-kn.utf-8: ಪೂರ್ವನಿಯೋಜಿತ ಕೀಲಿಮಣೆ (${XKBOPTIONS}) ಆಯ್ಕೆಗಳನ್ನು ಉಳಿಸಿಕೊಳ್ಳುವುದೇ?
Description-ko.utf-8: 키보드 옵션 기본값을 유지하시겠습니까 (${XKBOPTIONS})?
Description-ku.utf-8: Vebijêrkên klavyeya standard (${XKBOPTIONS})ê biparêze?
Description-lo.utf-8: ໂຕເລືອກແປ້ນພິມເກັບຄ່າເລີ່ມຕົ້ນ (${XKBOPTIONS})?
Description-lt.utf-8: Išlaikyti numatytąsias klaviatūros išdėstymo parinktis (${XKBOPTIONS})?
Description-lv.utf-8: Saglabāt noklusētos tastatūras iestatījumus (${XKBOPTIONS})?
Description-mk.utf-8: Зачувај го основниот распоред на тастатурата (${XKBOPTIONS})?
Description-ml.utf-8: സ്വതവേയുള്ള കീബോഡ് ക്രമീകരണം സൂക്ഷിക്കണോ (${XKBOPTIONS})?
Description-mr.utf-8: (${XKBOPTIONS}) हे मूलनिर्धारित कळफलक पर्याय ठेवायचे?
Description-nb.utf-8: Behold standard tastaturvalg (${XKBOPTIONS})?
Description-nl.utf-8: Standaard toetsenbordindeling (${XKBOPTIONS}) behouden?
Description-nn.utf-8: Hald på standard tastaturval (${XKBOPTIONS})?
Description-no.utf-8: Behold standard tastaturvalg (${XKBOPTIONS})?
Description-oc.utf-8: Conservar las opcions per defaut del clavièr (${XKBOPTIONS}) ?
Description-pa.utf-8: ਕੀ ਡੀਫਾਲਟ ਕੀ-ਬੋਰਡ ਲੇਆਉਟ ਰੱਖਣਾ ਹੈ (${XKBOPTIONS})?
Description-pl.utf-8: Zachować obecne opcje klawiatury (${XKBOPTIONS})?
Description-pt.utf-8: Manter as opções padrão do teclado (${XKBOPTIONS})?
Description-pt_br.utf-8: Manter as opções padrão de teclado (${XKBOPTIONS})?
Description-ro.utf-8: Se păstrează opțiunile implicite de tastatură (${XKBOPTIONS})?
Description-ru.utf-8: Оставить параметры клавиатуры (${XKBOPTIONS}), используемые по умолчанию?
Description-si.utf-8: පෙරනිමි යතුරුපුවරු අභිප්‍රේත (${XKBOPTIONS}) තබාගන්නද?
Description-sk.utf-8: Zachovať predvolené rozloženie klávesnice (${XKBOPTIONS})?
Description-sl.utf-8: Želite ohraniti privzete možnosti tipkovnice  (${XKBOPTIONS})?
Description-sq.utf-8: Mbaj opsionet e tastierës së parazgjedhur (${XKBOPTIONS})?
Description-sr.utf-8: Задржати подразумеване опције тастатуре (${XKBOPTIONS})?
Description-sr@latin.utf-8: Zadržati podrazumevane opcije tastature (${XKBOPTIONS})?
Description-sv.utf-8: Behåll standardalternativ för tangentbord (${XKBOPTIONS})?
Description-ta.utf-8: ${XKBOPTIONS} முன்னிருப்பு விசைப்பலகை தேர்வை வைத்துக்கொள்ளலாமா?
Description-te.utf-8: అప్రమేయ కీబోర్డు ఐచ్ఛికాలు  (${XKBOPTIONS}) అలాగే వుంచాలా?
Description-tg.utf-8: Имконоти пешфарзи ҳарфкалиди (${XKBOPTIONS})-ро нигоҳ медоред?
Description-th.utf-8: จะคงค่าตัวเลือกปริยายของแป้นพิมพ์ (${XKBOPTIONS}) หรือไม่?
Description-tr.utf-8: Öntanımlı klavye seçenekleri (${XKBOPTIONS}) kullanılmaya devam edilsin mi?
Description-ug.utf-8: كۆڭۈلدىكى ھەرپتاختا تاللانمىسى (${XKBOPTIONS})نى ساقلاپ قالامدۇ؟
Description-uk.utf-8: Залишити звичні налаштування клавіатури (${XKBOPTIONS})?
Description-vi.utf-8: Giữ tùy chọn phím mặc định (${XKBOPTIONS})?
Description-zh_cn.utf-8: 保留默认键盘选项 (${XKBOPTIONS})？
Description-zh_tw.utf-8: 是否保留預設鍵盤選項 (${XKBOPTIONS})？
Extended_description: The default value for the options of the keyboard layout is XKBOPTIONS="${XKBOPTIONS}".  It is based on the currently defined language/region and the settings in /etc/X11/xorg.conf.\n\nIf you choose to keep it, no questions about the keyboard options will be asked.
Extended_description-ar.utf-8: القيمة الافتراضية لخيارات مُخطط لوحة المفاتيح هي XKBOPTIONS="${XKBOPTIONS}".  وتلك القيمة مُحددة وفقاً للّغة/المنطقة والإعدادات في /etc/X11/xorg.conf.\n\nإن اخترت إبقاءه، فلن تسأل أي شيء عن خيارات لوحة المفاتيح.
Extended_description-ast.utf-8: El valor por defeutu pa les opciones del tecláu ye XKBOPTIONS="${XKBOPTIONS}". Ta basao nel territoriu/llingua definíos actualmente y na configuración en /etc/X11/xorg.conf.\n\nSi escueyes caltenelo, nun s'entrugará más sobre les opciones del tecláu.
Extended_description-be.utf-8: Перадвызначанае значэнне наладак клавіятуры: XKBOPTIONS="${XKBOPTIONS}".  Яно заснаванае на выбранай мове, рэгіёне і наладках у /etc/X11/xorg.conf.\n\nКалі вы вырашыце пакінуць гэта так, то не будзе задавацца ніякіх пытанняў пра наладкі клавіятуры.
Extended_description-bg.utf-8: Според указаните език/регион и настройките в /etc/X11/xorg.conf, опциите по подразбиране на клавиатурната подредба са XKBOPTIONS="${XKBOPTIONS}".\n\nАко изберете да ги запазите, няма да бъдат задавани повече въпроси за опциите на клавиатурата.
Extended_description-bn.utf-8: কীবোর্ড লেআউট অপশনের ডিফল্ট মান হল XKBOPTIONS="${XKBOPTIONS}". এটা বর্তমানে নির্দেশিত  language/region এবং /etc/X11/xorg.conf এর সেটিং এর উপর ভিত্তি করে করা হয়েছে.\n\nআপনি যদি এটা রাখতে পছন্দ করেন, তবে কীবোর্ড অপশন নিয়ে প্রশ্ন আর করা হবেনা।
Extended_description-bs.utf-8: Standardna vrijednost za postavke rasporeda tastera je XKBOPTIONS="${XKBOPTIONS}".  Bazirane su na trenutno definisanom jeziku/regionu i postavkama u /etc/X11/xorg.conf.\n\nAko izaberete da zadrži