develooper Front page | perl.perl5.porters | Postings from March 2008

Making more robust

Thread Next
Jan Dubois
March 25, 2008 17:06
Making more robust
Message ID:
I'm trying to make pl2bat a little more robust. It currently has the
annoying habit of executing e.g. a "foo" file found anywhere on the PATH
if I call the foo.bat simply as "foo", but will execute the content of
"foo.bat" (also located via PATH) if it can't find "foo" itself. This
generally will lead to weird results if for example you have a "foo" in
your current directory and it is not the one you expected to execute.

pl2bat generated batch files also look up perl.exe on the PATH instead
of loading it from the same tree as the batch file itself (when

I've tried to come up with some cmd.exe code that will try to determine
the full pathname of the batch file itself (which turned out to be
harder than I thought it would be because the whole %~ full path
expansion doesn't work correctly if %0 was given as a quoted string).

The script then tries to locate a "perl.exe" in the same directory (for
all scripts installed into perl/bin). Otherwise it checks if the batch
file is in a site/bin directory and tries to use ../../bin/perl.exe if
it exists before falling back to a PATH search.

Here is a little sample script that implements this logic. I would
appreciate if other Windows users could try it out to see if there are
any cases it doesn't cover correctly:

@echo off
setlocal enableextensions

set _BAT_=%~f0
if exist "%_BAT_%" goto findperl

set _BAT_=%_BAT_%.bat
if exist "%_BAT_%" goto findperl

set _BAT_=%~$PATH:0
if exist "%_BAT_%" goto findperl

for %%F in ("%~0.bat") do set _BAT_=%%~$PATH:F
if exist "%_BAT_%" goto findperl

echo *** Cannot find full path to %0 ***
goto :eof

echo BAT:  %_BAT_%

for %%F in ("%_BAT_%") do set _PERL_=%%~dpFperl.exe
if exist "%_PERL_%" goto runperl
if /i "%_PERL_:~-18%" equ "\site\bin\perl.exe" (
    set _PERL_=%_PERL_:~0,-18%\bin\perl.exe
if not exist "%_PERL_%" set _PERL_=perl

echo PERL: %_PERL_%
"%_PERL_%" -we "print '$^X:  ', $^X"
goto :eof

I think I tried most combinations of the following, but maybe I'm
forgetting about some other special cases:

* put the script into a directory with spaces in the name
* use a filename containing spaces for the script
* put the script into the Perl/bin directory
* put the script into the Perl/site/bin directory
* invoke the script by name, with and without .bat extension
* put quotes around the script name when you invoke it
* use absolute and relative path names to invoke it
* use shortcuts in the Start menu to run the script

As far as I can tell it is now always finding the correct absolute
pathname for the batch file itself. Let me know if you can come up with
a scenario that leads to the "*** Cannot find full path" error message.

I'll integrate this code into (and if we can agree
that it is more robust than the current logic (note that the current
code already uses %*, so it already assumes that cmd.exe extensions are
available and enabled).

Oops, forgot to mention: all this code is for the Windows_NT branch
only; I don't think there is anything we can do for Win9X.


PS: Here are some notes I wrote while writing the code to determine
    _BAT_ above:

There are 6 different scenarios:

1) unqoted command name, with or without path
   - %~f0 expansion works

2) quoted command name, includes relative or absolute path
   - %~f0 expansion works

3) quoted command name, .bat file extension specified, in current directory
   - %~f0 expansion accidentally produces the correct result
   - must check manually because %~$PATH:0 does not find it

4) quoted command name, no file extension, in current directory
   - %~f0 expansion is missing the .bat file extension

5) quoted command name, .bat file extension specified, on PATH
   - %~f0 wrongly contains current directory name followed by command name
   - %~$PATH:0 finds the batch file on the PATH

6) quoted command name, no file extension, on PATH
   - %~f0 wrongly contains current directory name followed by command name
   - must look for "%~0.bat" on PATH
   - must be tested after 4 so that foo.bat finds foo.bat in preferance of
     foo.bat.bat if both files exist somewhere on the PATH (this is not
     not completely correct, but close enough).

The whole "look up in $VAR path list" feature seems very simplistic; it
doesn't implement the usual PATH search logic used by CreateProcess() and/or

Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About