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