From: Tom Christiansen <tchrist@convex.COM>
Subject: Re: scripts should indicate the Perl version (a proposal)
Originator: tchrist@pixel.convex.com
Date: Tue, 10 Nov 1992 15:42:30 GMT
Reply-To: tchrist@convex.COM (Tom Christiansen)
Organization: Convex Computer Corporation, Colorado Springs, CO
X-Disclaimer: This message was written by a user at CONVEX Computer
              Corp. The opinions expressed are those of the user and
              not necessarily those of CONVEX.

From the keyboard of mcook@fendahl.dev.cdx.mot.com (Michael Cook):
:How about this idea: There should be a way to specify in a Perl script what
:version of Perl the script was written for.  Then, as new keywords and other
:non-backwardly-compatible functionality are added, old scripts could still
:likely work correctly.  For example, these two scripts might behave
:differently:
:
: #! /usr/local/bin/perl
: version 2.0;
: print "1" | "2";
:
: #! /usr/local/bin/perl
: version 4.0;
: print "1" | "2";
:
:because the | operator's meaning changed between Perl versions 2.0 and 4.0 (or
:whenever).  With the first script, perl would see the "version 2.0" statement,
:and disable that new meaning associated with the | operator.
:
:Make sense?

The problem with this is that if you introduce this with perl5,
none of those work with earlier released of perl because they don't 
grok 'version'.  

I think it's time to reintroduce my preamulate script, which 
you run on a perl script to make another one which has version 
sanity checking in it.  

Of course, like most of my interesting programs, this one is 
subject to the evil "Malformed cmd links" aborting behavior.
Some scripts have the problem, some don't.  If you get a little
one that does, Larry would love to have it.  For example, my
'man' program works fine this way, but 'zap' blows up.  Sure
wish I knew why, as do many others, so badly it's now a FAQ.

#!/usr/local/bin/perl
#
# preambulate -- wrap a perl program with a system-independent preamble.  
#
# Tom Christiansen tchrist@convex.com

$mypath = '/usr/local/bin/perl';
($myversion, $mypatchlevel) = $] =~ /(\d+\.\d+).*\nPatch level: (\d+)/;


unless (@ARGV) {
    unshift(@ARGV, '-');
    $was_stdin++;
}

while ($file = shift) {
    open file || die "can't open $file: $!";
    $mode = (stat(file))[2] & 0777;
    if ($file ne '-') {
	$TMP = "$file.tmp";
	open (TMP, ">$TMP") || die "can't create $TMP: $!"; 
     } else {
	open (TMP, ">&STDOUT");
     } 
     print TMP <<'EOF';
#!/bin/sh -- need to mention perl here to avoid recursion

'true' || eval 'exec perl -S $0 $argv:q';
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
& eval 'exec perl -S $0 $argv:q'
        if 0;

VERSION_SANITY: {
    package VERSION_SANITY;
    local($_);
EOF
    print TMP <<"EOF";
    \$PERL_PATH = '$mypath';
    local(\$version, \$patchlevel) = ($myversion, $mypatchlevel);
EOF

    print TMP <<'EOF';

    local($want_vp) = sprintf("%d.%03d", $version, $patchlevel);
    local($need_perl) = $PERL_PATH . $want_vp;

    die "can't get version" 
	unless $] =~ /(\d+\.\d+).*\nPatch level: (\d+)/;

    sub try_version {
        warn "current perl version ($got_vp) too low, execing $need_perl\n";
        exec $need_perl, $0, @ARGV;
        warn "exec of $need_perl failed: $!";
    }

    if ($1 < $version || $2 < $patchlevel) { 
	local($got_vp) =  sprintf("%d.%03d", $1, $2);
        &try_version if -x $need_perl;
        for $need_perl (reverse sort </usr/local/bin/perl* /usr/bin/perl*>) {
            next unless $need_perl =~ /perl(\d+)\.(\d+)$/;
            &try_version if $1 >= $version && $2 >= $patchlevel;
        }
        warn "WARNING: perl version too low: $got_vp < $want_vp; good luck...\n";
    } 
} 

@VS'info = (__FILE__, __LINE__); eval <<'___VERSION_SANITY___';

# BEGIN REAL PROGRAM

EOF

    while (<file>) {
	print TMP;
    } 

    print TMP <<'EOF';


# END REAL PROGRAM

___VERSION_SANITY___


if ($@) {
    $_ = $@;
    ($file, $line) =  @VS'info;
    s/ file \(eval\) at line (\d+)/" $file at line " .  ($1 + $line)/eg;
    s/ at \(eval\) line (\d+)/" in $file at line " .  ($1 + $line)/eg;
    die $_;;
}

exit 0;

EOF

    unless ($file eq '-') {
	close TMP;
	chmod $mode, $TMP;
	rename ($file, "$file.bak") || die "can't rename $file to $file.bak: $!";
	rename ($TMP, $file) || die "can't rename $TMP to $file: $!";
    }
}

__END__

--tom
-- 
    Tom Christiansen      tchrist@convex.com      convex!tchrist
The cause of the riots were the rioters
                --Vice President Dan Quayle giving an intelligent 
                  analysis of the LA riots.
Newsgroups: comp.lang.perl