1 eval 'exec perl -x -S "$0" ${1+"$@"}' 2 if 0; # In case running under some shell 3 4require 5; 5use Getopt::Std; 6use Config; 7 8$0 =~ s|.*[/\\]||; 9 10my $usage = <<EOT; 11Usage: $0 [-h] 12 or: $0 [-w] [-u] [-a argstring] [-s stripsuffix] [files] 13 or: $0 [-w] [-u] [-n ntargs] [-o otherargs] [-s stripsuffix] [files] 14 -n ntargs arguments to invoke perl with in generated file 15 when run from Windows NT. Defaults to 16 '-x -S %0 %*'. 17 -o otherargs arguments to invoke perl with in generated file 18 other than when run from Windows NT. Defaults 19 to '-x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9'. 20 -a argstring arguments to invoke perl with in generated file 21 ignoring operating system (for compatibility 22 with previous pl2bat versions). 23 -u update files that may have already been processed 24 by (some version of) pl2bat. 25 -w include "-w" on the /^#!.*perl/ line (unless 26 a /^#!.*perl/ line was already present). 27 -s stripsuffix strip this suffix from file before appending ".bat" 28 Not case-sensitive 29 Can be a regex if it begins with '/' 30 Defaults to "/\.plx?/" 31 -h show this help 32EOT 33 34my %OPT = (); 35warn($usage), exit(0) if !getopts('whun:o:a:s:',\%OPT) or $OPT{'h'}; 36# NOTE: %0 is already enclosed in double quotes by cmd.exe, as appropriate 37$OPT{'n'} = '-x -S %0 %*' unless exists $OPT{'n'}; 38$OPT{'o'} = '-x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9' unless exists $OPT{'o'}; 39$OPT{'s'} = '/\\.plx?/' unless exists $OPT{'s'}; 40$OPT{'s'} = ($OPT{'s'} =~ m#^/([^/]*[^/\$]|)\$?/?$# ? $1 : "\Q$OPT{'s'}\E"); 41 42my $head; 43if( defined( $OPT{'a'} ) ) { 44 $head = <<EOT; 45 \@rem = '--*-Perl-*-- 46 \@echo off 47 perl $OPT{'a'} 48 goto endofperl 49 \@rem '; 50EOT 51} else { 52 $head = <<EOT; 53 \@rem = '--*-Perl-*-- 54 \@echo off 55 if "%OS%" == "Windows_NT" goto WinNT 56 perl $OPT{'o'} 57 goto endofperl 58 :WinNT 59 perl $OPT{'n'} 60 if NOT "%COMSPEC%" == "%SystemRoot%\\system32\\cmd.exe" goto endofperl 61 if %errorlevel% == 9009 echo You do not have Perl in your PATH. 62 if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul 63 goto endofperl 64 \@rem '; 65EOT 66} 67$head =~ s/^\t//gm; 68my $headlines = 2 + ($head =~ tr/\n/\n/); 69my $tail = "\n__END__\n:endofperl\n"; 70 71@ARGV = ('-') unless @ARGV; 72 73foreach ( @ARGV ) { 74 process($_); 75} 76 77sub process { 78 my( $file )= @_; 79 my $myhead = $head; 80 my $linedone = 0; 81 my $taildone = 0; 82 my $linenum = 0; 83 my $skiplines = 0; 84 my $line; 85 my $start= $Config{startperl}; 86 $start= "#!perl" unless $start =~ /^#!.*perl/; 87 open( FILE, '<', $file ) or die "$0: Can't open $file: $!"; 88 @file = <FILE>; 89 foreach $line ( @file ) { 90 $linenum++; 91 if ( $line =~ /^:endofperl\b/ ) { 92 if( ! exists $OPT{'u'} ) { 93 warn "$0: $file has already been converted to a batch file!\n"; 94 return; 95 } 96 $taildone++; 97 } 98 if ( not $linedone and $line =~ /^#!.*perl/ ) { 99 if( exists $OPT{'u'} ) { 100 $skiplines = $linenum - 1; 101 $line .= "#line ".(1+$headlines)."\n"; 102 } else { 103 $line .= "#line ".($linenum+$headlines)."\n"; 104 } 105 $linedone++; 106 } 107 if ( $line =~ /^#\s*line\b/ and $linenum == 2 + $skiplines ) { 108 $line = ""; 109 } 110 } 111 close( FILE ); 112 $file =~ s/$OPT{'s'}$//oi; 113 $file .= '.bat' unless $file =~ /\.bat$/i or $file =~ /^-$/; 114 open( FILE, '>', $file ) or die "Can't open $file: $!"; 115 print FILE $myhead; 116 print FILE $start, ( $OPT{'w'} ? " -w" : "" ), 117 "\n#line ", ($headlines+1), "\n" unless $linedone; 118 print FILE @file[$skiplines..$#file]; 119 print FILE $tail unless $taildone; 120 close( FILE ); 121} 122__END__ 123 124=head1 NAME 125 126pl2bat - wrap perl code into a batch file 127 128=head1 SYNOPSIS 129 130B<pl2bat> B<-h> 131 132B<pl2bat> [B<-w>] S<[B<-a> I<argstring>]> S<[B<-s> I<stripsuffix>]> [files] 133 134B<pl2bat> [B<-w>] S<[B<-n> I<ntargs>]> S<[B<-o> I<otherargs>]> S<[B<-s> I<stripsuffix>]> [files] 135 136=head1 DESCRIPTION 137 138This utility converts a perl script into a batch file that can be 139executed on DOS-like operating systems. This is intended to allow 140you to use a Perl script like regular programs and batch files where 141you just enter the name of the script [probably minus the extension] 142plus any command-line arguments and the script is found in your B<PATH> 143and run. 144 145=head2 ADVANTAGES 146 147There are several alternatives to this method of running a Perl script. 148They each have disadvantages that help you understand the motivation 149for using B<pl2bat>. 150 151=over 152 153=item 1 154 155 C:> perl x:/path/to/script.pl [args] 156 157=item 2 158 159 C:> perl -S script.pl [args] 160 161=item 3 162 163 C:> perl -S script [args] 164 165=item 4 166 167 C:> ftype Perl=perl.exe "%1" %* 168 C:> assoc .pl=Perl 169 then 170 C:> script.pl [args] 171 172=item 5 173 174 C:> ftype Perl=perl.exe "%1" %* 175 C:> assoc .pl=Perl 176 C:> set PathExt=%PathExt%;.PL 177 then 178 C:> script [args] 179 180=back 181 182B<1> and B<2> are the most basic invocation methods that should work on 183any system [DOS-like or not]. They require extra typing and require 184that the script user know that the script is written in Perl. This 185is a pain when you have lots of scripts, some written in Perl and some 186not. It can be quite difficult to keep track of which scripts need to 187be run through Perl and which do not. Even worse, scripts often get 188rewritten from simple batch files into more powerful Perl scripts in 189which case these methods would require all existing users of the scripts 190be updated. 191 192B<3> works on modern Win32 versions of Perl. It allows the user to 193omit the ".pl" or ".bat" file extension, which is a minor improvement. 194 195B<4> and B<5> work on some Win32 operating systems with some command 196shells. One major disadvantage with both is that you can't use them 197in pipelines nor with file redirection. For example, none of the 198following will work properly if you used method B<4> or B<5>: 199 200 C:> script.pl <infile 201 C:> script.pl >outfile 202 C:> echo y | script.pl 203 C:> script.pl | more 204 205This is due to a Win32 bug which Perl has no control over. This bug 206is the major motivation for B<pl2bat> [which was originally written 207for DOS] being used on Win32 systems. 208 209Note also that B<5> works on a smaller range of combinations of Win32 210systems and command shells while B<4> requires that the user know 211that the script is a Perl script [because the ".pl" extension must 212be entered]. This makes it hard to standardize on either of these 213methods. 214 215=head2 DISADVANTAGES 216 217There are several potential traps you should be aware of when you 218use B<pl2bat>. 219 220The generated batch file is initially processed as a batch file each 221time it is run. This means that, to use it from within another batch 222file you should precede it with C<call> or else the calling batch 223file will not run any commands after the script: 224 225 call script [args] 226 227Except under Windows NT, if you specify more than 9 arguments to 228the generated batch file then the 10th and subsequent arguments 229are silently ignored. 230 231Except when using F<CMD.EXE> under Windows NT, if F<perl.exe> is not 232in your B<PATH>, then trying to run the script will give you a generic 233"Command not found"-type of error message that will probably make you 234think that the script itself is not in your B<PATH>. When using 235F<CMD.EXE> under Windows NT, the generic error message is followed by 236"You do not have Perl in your PATH", to make this clearer. 237 238On most DOS-like operating systems, the only way to exit a batch file 239is to "fall off the end" of the file. B<pl2bat> implements this by 240doing C<goto :endofperl> and adding C<__END__> and C<:endofperl> as 241the last two lines of the generated batch file. This means: 242 243=over 244 245=item No line of your script should start with a colon. 246 247In particular, for this version of B<pl2bat>, C<:endofperl>, 248C<:WinNT>, and C<:script_failed_so_exit_with_non_zero_val> should not 249be used. 250 251=item Care must be taken when using C<__END__> and the C<DATA> file handle. 252 253One approach is: 254 255 . #!perl 256 . while( <DATA> ) { 257 . last if /^__END__$/; 258 . [...] 259 . } 260 . __END__ 261 . lines of data 262 . to be processed 263 . __END__ 264 . :endofperl 265 266The dots in the first column are only there to prevent F<cmd.exe> to interpret 267the C<:endofperl> line in this documentation. Otherwise F<pl2bat.bat> itself 268wouldn't work. See the previous item. :-) 269 270=item The batch file always "succeeds" 271 272The following commands illustrate the problem: 273 274 C:> echo exit(99); >fail.pl 275 C:> pl2bat fail.pl 276 C:> perl -e "print system('perl fail.pl')" 277 99 278 C:> perl -e "print system('fail.bat')" 279 0 280 281So F<fail.bat> always reports that it completed successfully. Actually, 282under Windows NT, we have: 283 284 C:> perl -e "print system('fail.bat')" 285 1 286 287So, for Windows NT, F<fail.bat> fails when the Perl script fails, but 288the return code is always C<1>, not the return code from the Perl script. 289 290=back 291 292=head2 FUNCTION 293 294By default, the ".pl" suffix will be stripped before adding a ".bat" suffix 295to the supplied file names. This can be controlled with the C<-s> option. 296 297The default behavior is to have the batch file compare the C<OS> 298environment variable against C<"Windows_NT">. If they match, it 299uses the C<%*> construct to refer to all the command line arguments 300that were given to it, so you'll need to make sure that works on your 301variant of the command shell. It is known to work in the F<CMD.EXE> shell 302under Windows NT. 4DOS/NT users will want to put a C<ParameterChar = *> 303line in their initialization file, or execute C<setdos /p*> in 304the shell startup file. 305 306On Windows95 and other platforms a nine-argument limit is imposed 307on command-line arguments given to the generated batch file, since 308they may not support C<%*> in batch files. 309 310These can be overridden using the C<-n> and C<-o> options or the 311deprecated C<-a> option. 312 313=head1 OPTIONS 314 315=over 8 316 317=item B<-n> I<ntargs> 318 319Arguments to invoke perl with in generated batch file when run from 320Windows NT (or Windows 98, probably). Defaults to S<'-x -S %0 %*'>. 321 322=item B<-o> I<otherargs> 323 324Arguments to invoke perl with in generated batch file except when 325run from Windows NT (ie. when run from DOS, Windows 3.1, or Windows 95). 326Defaults to S<'-x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9'>. 327 328=item B<-a> I<argstring> 329 330Arguments to invoke perl with in generated batch file. Specifying 331B<-a> prevents the batch file from checking the C<OS> environment 332variable to determine which operating system it is being run from. 333 334=item B<-s> I<stripsuffix> 335 336Strip a suffix string from file name before appending a ".bat" 337suffix. The suffix is not case-sensitive. It can be a regex if 338it begins with '/' (the trailing '/' is optional and a trailing 339C<$> is always assumed). Defaults to C</.plx?/>. 340 341=item B<-w> 342 343If no line matching C</^#!.*perl/> is found in the script, then such 344a line is inserted just after the new preamble. The exact line 345depends on C<$Config{startperl}> [see L<Config>]. With the B<-w> 346option, C<" -w"> is added after the value of C<$Config{startperl}>. 347If a line matching C</^#!.*perl/> already exists in the script, 348then it is not changed and the B<-w> option is ignored. 349 350=item B<-u> 351 352If the script appears to have already been processed by B<pl2bat>, 353then the script is skipped and not processed unless B<-u> was 354specified. If B<-u> is specified, the existing preamble is replaced. 355 356=item B<-h> 357 358Show command line usage. 359 360=back 361 362=head1 EXAMPLES 363 364 C:\> pl2bat foo.pl bar.PM 365 [..creates foo.bat, bar.PM.bat..] 366 367 C:\> pl2bat -s "/\.pl|\.pm/" foo.pl bar.PM 368 [..creates foo.bat, bar.bat..] 369 370 C:\> pl2bat < somefile > another.bat 371 372 C:\> pl2bat > another.bat 373 print scalar reverse "rekcah lrep rehtona tsuj\n"; 374 ^Z 375 [..another.bat is now a certified japh application..] 376 377 C:\> ren *.bat *.pl 378 C:\> pl2bat -u *.pl 379 [..updates the wrapping of some previously wrapped scripts..] 380 381 C:\> pl2bat -u -s .bat *.bat 382 [..same as previous example except more dangerous..] 383 384=head1 BUGS 385 386C<$0> will contain the full name, including the ".bat" suffix 387when the generated batch file runs. If you don't like this, 388see runperl.bat for an alternative way to invoke perl scripts. 389 390Default behavior is to invoke Perl with the B<-S> flag, so Perl will 391search the B<PATH> to find the script. This may have undesirable 392effects. 393 394On really old versions of Win32 Perl, you can't run the script 395via 396 397 C:> script.bat [args] 398 399and must use 400 401 C:> script [args] 402 403A loop should be used to build up the argument list when not on 404Windows NT so more than 9 arguments can be processed. 405 406See also L</DISADVANTAGES>. 407 408=head1 SEE ALSO 409 410perl, perlwin32, runperl.bat 411 412=cut 413 414